tarjan缩点,找入度为0的点(可能是一条链的端点或者一个点),入度为0的点必须能被控制。
每个强连通分量中能被控制的点的最小值是缩点后这个点的最小值,入度为0的点的最小值的和就是最小花费。
还要记下每个强连通分量中的最小编号,这些编号中的最小值就是第一个不能被控制的点。
#include<iostream> #include<cstdio> #include<cstring> #define N 3010 using namespace std; struct edge { int to,next; }e[N*2],d[N*2]; int head[N],h[N]; int w[N],W[N]; bool instack[N]; int low[N],dfn[N],stack[N]; int cost[N],MIN[N]; int belong[N],rudu[N]; int Index,scc,cnt,top,r; int n,p,x,y,u,v; void ins(int u,int v) { e[++cnt].to = v; e[cnt].next = head[u]; head[u] = cnt; } void tarjan(int k) { dfn[k] = low[k] = ++Index; stack[++top] = k; instack[k] = true; for (int i=head[k];i;i = e[i].next) { int v = e[i].to; if (instack[v]) low[k] = min(low[k],dfn[v]); else if (!dfn[v]) { tarjan(v); low[k] = min(low[k],low[v]); } } if (dfn[k] == low[k]) { scc++; int now = 0; while (now != k) { now = stack[top--]; belong[now] = scc; instack[now] = false; if (w[now]) { W[scc] = min(W[scc],w[now]); } MIN[scc] = min(MIN[scc],now); } } } int main() { memset(W,127,sizeof(W)); memset(MIN,127,sizeof(MIN)); scanf("%d%d",&n,&p); for (int i=1;i<=p;i++) { scanf("%d%d",&x,&y); w[x] = y; } scanf("%d",&r); for (int i=1;i<=r;i++) { scanf("%d%d",&u,&v); ins(u,v); } for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i); cnt = 0; for (int i=1;i<=n;i++) { for (int j = head[i];j;j = e[j].next) { int v = e[j].to; if (belong[i] != belong[v]) { d[++cnt].to = belong[v]; d[cnt].next = h[belong[i]]; h[belong[i]] = ++cnt; rudu[belong[v]] ++; } } } int pd=0,failmin=6666666,ans = 0; for (int i=1;i<=scc;i++) { if (rudu[i] == 0) { if (W[i] == 2139062143) { pd = 1; failmin = min(failmin,MIN[i]); } ans += W[i]; } } if (pd == 1) { printf("NO\n"); printf("%d",failmin); return 0; } printf("YES\n%d",ans); }