您的位置:首页 > 其它

bzoj2438: [中山市选2011]杀人游戏(强联通)

2017-11-26 16:17 330 查看
题目传送门

强啊。

解法:

强联通还是蛮好看出来的呀。

然后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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: