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

本文介绍了一种基于强联通分量的算法实现思路,通过深度优先搜索确定强联通分量,并进一步分析了如何利用这些信息解决特定问题。文章讨论了特殊情况下的处理方式,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目传送门
强啊。

解法:
强联通还是蛮好看出来的呀。
然后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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值