bzoj2438: [中山市選2011]殺人遊戲(強聯通)

Hanks_o發表於2017-11-26

題目傳送門
強啊。

解法:
強聯通還是蠻好看出來的呀。
然後yy了一個解法錯了半天。
然後艹哥告訴我有特殊情況?!
那麼相對於每一個聯通塊。如果他的入度為0那麼肯定從它開始問呀。
因為入度不為0的話你問別人肯定問的到它。
所以相對於每一個入度為0的塊就有機會被殺死。
如果有一個大小為1的連通塊且它入度為0、無出度或者連到的連通塊都還有別人連它
那它就可以不選 ans-

程式碼實現:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
struct node {int x,y,next;}a[310000],e[310000];int len,last[110000];
void ins(int x,int y) {len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
int elen,last1[110000];void ins1(int x,int y) {elen++;e[elen].x=x;e[elen].y=y;e[elen].next=last1[x];last1[x]=elen;}
int low[110000],dfn[110000],sta[110000],tp,cnt,id,s[110000],belong[110000];bool v[110000];
void dfs(int x) {
    low[x]=dfn[x]=++id;sta[++tp]=x;v[x]=true;
    for(int k=last[x];k;k=a[k].next) {
        int y=a[k].y;if(dfn[y]==-1){dfs(y);low[x]=min(low[x],low[y]);}
        else if(v[y]==true)low[x]=min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x]) {int i;cnt++;do {i=sta[tp--];v[i]=false;belong[i]=cnt;s[cnt]++;}while(i!=x);}
}                                       
int ru[110000],tot[110000];
int check(int x) {
    if(s[belong[x]]!=1||ru[belong[x]]!=0)return 0;
    for(int k=last[x];k;k=a[k].next)if(ru[belong[a[k].y]]==1)return 0;
    return 1;
}
int main() {
    int n,m;scanf("%d%d",&n,&m);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=m;i++) {int x,y;scanf("%d%d",&x,&y);ins(x,y);}
    memset(s,0,sizeof(s));memset(dfn,-1,sizeof(dfn));
    cnt=id=tp=0;memset(v,false,sizeof(v));memset(sta,0,sizeof(sta));
    for(int i=1;i<=n;i++)if(dfn[i]==-1)dfs(i);
    memset(ru,0,sizeof(ru));
    for(int i=1;i<=len;i++) if(belong[a[i].x]!=belong[a[i].y])ru[belong[a[i].y]]++;
    int ss=0,ans=0;for(int i=1;i<=cnt;i++) if(ru[i]==0)ans++;
    for(int i=1;i<=n;i++)if(check(i)==1){ans--;break;}
    printf("%.6lf\n",double(n-ans)/double(n));
    return 0;
}

相關文章