洛谷1262 間諜網路 tarjan縮點
阿新 • • 發佈:2018-12-10
這個題首先tarjan縮個點,然後統計各個縮完之後的點的中被收買人的最小值,假如某個強連通分量的入度為0,那就收買他,我實在是太蒟蒻了想了半天怎麼判斷NO的情況想不通一直卡在92,後來看了題解恍然大悟。假如一個人不能被收買,那我就直接在targin的時候不搜這個點,那麼之後遍歷一遍dfn,如果存在0,就說明有一個人既不能被舉報,也不能被收買,輸出NO和編號即可。附上程式碼:
#include<stdio.h> #include<stdlib.h> #include<string.h> int s[100001]={0},low[100001]={0},dfn[100001]={0},co[100001]={0},buy[100001]={0},d1[100001]={0}; int x[100001]={0},y[100001]={0},nxt[100001]={0},head[100001]={0},to[100001]={0},min1[100001]={0},d2[100001]={0}; int tmp=0,num=0,top=0,col=0,n,p,r; int min(int x,int y) { if(x>y) return y; else return x; } int add(int x,int y) { tmp++; to[tmp]=y; nxt[tmp]=head[x]; head[x]=tmp; return 0; } int tarjan(int i) { int j,t; num++;top++; s[top]=i;low[i]=num;dfn[i]=num; for(j=head[i];j;j=nxt[j]) { t=to[j]; if(dfn[t]==0) { tarjan(t); low[i]=min(low[i],low[t]); } else if(co[t]==0) { low[i]=min(low[i],low[t]); } } if(dfn[i]==low[i]) { col++; co[i]=col; if(buy[i]!=0) min1[col]=buy[i]; while(s[top]!=i) { co[s[top]]=col; if(buy[s[top]]!=0) min1[col]=min(min1[col],buy[s[top]]); top--; } top--; } return 0; } int main() { int i,j,ans=0,u,t; scanf("%d%d",&n,&p); for(i=1;i<=5000;i++) min1[i]=1000000; for(i=1;i<=p;i++) { scanf("%d",&u); scanf("%d",&buy[u]); } scanf("%d",&r); for(i=1;i<=r;i++) { scanf("%d%d",&x[i],&y[i]); add(x[i],y[i]); } for(i=1;i<=n;i++) if(dfn[i]==0&&buy[i]!=0) tarjan(i); for(i=1;i<=n;i++) if(dfn[i]==0) { printf("NO\n%d",i); return 0; } memset(head,0,sizeof(head)); memset(to,0,sizeof(to)); memset(nxt,0,sizeof(nxt)); tmp=0; for(i=1;i<=r;i++) if(co[x[i]]!=co[y[i]]) { add(co[x[i]],co[y[i]]); } for(i=1;i<=col;i++) { for(j=head[i];j;j=nxt[j]) { t=to[j]; d1[i]++;d2[t]++; } } for(i=1;i<=col;i++) if(d2[i]==0) ans+=min1[i]; printf("YES\n"); printf("%d",ans); return 0; }