终于有一道能够一次AC的Tarjan题啦!
这个题还是很简单的,首先Tarjan缩点,之后把新图建出来之后发现,因为要控制所有间谍,那么肯定得从入度为0的间谍下手,所以如果有任何入度为0的间谍不愿意被收买的话任务就失败了,否则的话直接topo排序统计答案即可。
图也许是不联通的,所以要用循环的方法一直跑即可。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<queue> #include<set> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar(' ') using namespace std; typedef long long ll; const int M = 50005; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct edge { int next,to,from; }e[M],e1[M]; int n,p,r,a,b,low[M],dfn[M],stack[M],scc[M],mmoney[M],mnode[M],head[M],ecnt,idx,cnt,top; int rdeg[M],cdeg[M],ecnt1,head1[M],mo[M],ans; bool vis[M],pd[M],can[M],jud[M]; void add(int x,int y) { e[++ecnt].to = y; e[ecnt].from = x; e[ecnt].next = head[x]; head[x] = ecnt; } void add1(int x,int y) { e[++ecnt1].to = y; e[ecnt1].from = x; e[ecnt1].next = head1[x]; head1[x] = ecnt1; } void tarjan(int x) { low[x] = dfn[x] = ++idx; stack[++top] = x,vis[x] = 1; for(int i = head[x];i;i = e[i].next) { if(!dfn[e[i].to]) tarjan(e[i].to),low[x] = min(low[x],low[e[i].to]); else if(vis[e[i].to]) low[x] = min(low[x],dfn[e[i].to]); } if(low[x] == dfn[x]) { cnt++; int p; while((p = stack[top--])) { scc[p] = cnt,vis[p] = 0; if(can[p]) jud[cnt] = 1,mmoney[cnt] = (!mmoney[cnt]) ? mo[p] : min(mmoney[cnt],mo[p]); mnode[cnt] = (!mnode[cnt]) ? p : min(p,mnode[cnt]); if(p == x) break; } } } void rebuild() { rep(i,1,ecnt) { int r1 = scc[e[i].from],r2 = scc[e[i].to]; //printf("@%d %d ",r1,r2); if(r1 != r2) add1(r1,r2),rdeg[r2]++,cdeg[r1]++; } } void topo(int x) { if(!jud[x]) { printf("NO "); printf("%d ",mnode[x]); exit(0); } queue <int> q; q.push(x);pd[x] = 1,ans += mmoney[x]; while(!q.empty()) { int k = q.front();q.pop(); for(int i = head1[k];i;i = e1[i].next) { cdeg[k]--,rdeg[e1[i].to]--; if(!rdeg[e1[i].to]) q.push(e1[i].to); } } } int main() { n = read(),p = read(); rep(i,1,p) a = read(),b = read(),can[a] = 1,mo[a] = b; r = read(); rep(i,1,r) a = read(),b = read(),add(a,b); //rep(i,1,ecnt) printf("!%d %d ",e[i].from,e[i].to); rep(i,1,n) if(!dfn[i]) tarjan(i); rebuild(); //rep(i,1,ecnt1) printf("#%d %d ",e1[i].from,e1[i].to); rep(i,1,cnt) if(!pd[i] && !rdeg[i]) topo(i); printf("YES "); printf("%d ",ans); return 0; }