bzoj2438: [中山市选2011]杀人游戏
感觉今天状态起飞了!!!之前留的坑一调就A了,舒服!!!
那么这题之前一看就觉得,假如一个人没人认识实际上他必须查一下,那么我第一次做的时候就把他抽象成了很多棵树,然后我只查树根,然后下面的每一层我都知道身份,那就没有生命之忧了。然后特判一下有一个人没人认识tata也不认识别人,就是自己独立出来的,那他最后留下来实际上不用查。
然后实际上这题怎么可能这么简单,肯定会构环的,那么就考虑强连通缩点,那么这题难就难在怎么判最后查剩一个人的情况了,那么具体怎么做呢?首先这个点入度肯定为0的,再者这个联通块肯定是只有一个点,不然还是需要问的,第三查他所能得知的点入度要>1,否则的话说明这个点必须通过当前这个点才能得知身份,还是需要查他。所以说这题细节还是很多的,搞得那时候感冒晕乎乎的。。。。
#include<cstdio> #include<iostream> #include<cstring> using namespace std; int n,m; struct node { int x,y,next; }a[310000],e[310000];int len,last[1100000],elen,elast[1100000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } void eins(int x,int y) { elen++; e[elen].x=x;e[elen].y=y; e[elen].next=elast[x];elast[x]=elen; } int id,dfn[1100000],low[1100000]; int top,sta[1100000]; int cnt,belong[1100000],size[1100000]; bool v[1100000]; void strong_unicom(int x) { dfn[x]=low[x]=++id; sta[++top]=x; v[x]=true; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(dfn[y]==0) { strong_unicom(y); low[x]=min(low[x],low[y]); } else if(v[y]==true) { low[x]=min(low[x],dfn[y]); } } if(dfn[x]==low[x]) { int i;cnt++; do { i=sta[top];top--; belong[i]=cnt; v[i]=false; size[cnt]++; }while(i!=x); } } int ru[1100000]; bool check(int x) { if(size[x]!=1)return true; if(elast[x]==0)return false; for(int k=elast[x];k;k=e[k].next) { int y=e[k].y; if(ru[y]<=1)return true; } return false; } int main() { int x,y; scanf("%d%d",&n,&m); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); ins(x,y); } id=0;top=0;cnt=0; memset(dfn,0,sizeof(dfn)); memset(v,false,sizeof(v)); memset(size,0,sizeof(size)); for(int i=1;i<=n;i++) if(dfn[i]==0) strong_unicom(i); memset(ru,0,sizeof(ru)); elen=0;memset(elast,0,sizeof(elast)); for(int i=1;i<=m;i++) { x=belong[a[i].x],y=belong[a[i].y]; if(x!=y) { ru[y]++; eins(x,y); } } int sum=0; for(int i=1;i<=cnt;i++) if(ru[i]==0)sum++; for(int i=1;i<=cnt;i++) if(ru[i]==0) if(check(i)==false){sum--;break;} printf("%.6lf\n",1.0-double(sum)/double(n)); return 0; }
pain and happy in the cruel world.