fzu 1719 强连通分量 缩点
题意:有n个间谍,其中r个花钱可以买通,间谍手上有其他间谍的证据。问能否控制所有间谍。能的话输出最小的钱数,不能的话输出最小的不能被控制的间谍ID。
分析:缩点后的价值取环内最小的价值,然后把入度为0的间谍全部买下来。
#define M 3011 struct Node{ int v,next;//next要初始化为-1 }edge[15001]; int n , nn , len; int old[M],now[M]; int tim[M],t; int low[M],hash[M],hp[M];//原结点向新结点映射 新边判重 int sta[M],top; int cost[M]; int sum,minid; int id[M],s[M],rudu[M]; void dfs(int u) { tim[u] = low[u] = t ++; sta[++top] = u; for(int i = old[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if(tim[v] == -1) { dfs(v); checkmin(low[u],low[v]); } else if(hash[v] == -1) { checkmin(low[u],low[v]);//low[v]貌似也可以??? } } if(tim[u] == low[u]) { id[nn]=-1,s[nn]=99999999; int v = -1; while(u != v) { v = sta[top--]; checkmin(id[nn],v); if(cost[v]>0 && s[nn]>cost[v]) s[nn]=cost[v]; hash[v] = nn; } rudu[nn]=0; now[nn++] = -1; } } void Trajan() { FOR(i,1,n+1) if(tim[i] == -1) { dfs(i); } FOR(u,1,n+1) { for(int i = old[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if(hash[u] != hash[v] && hp[hash[u]] != hash[v]) { rudu[ hash[v] ] ++; hp[hash[u]] = hash[v]; //新边的判重貌似有问题 edge[len].next = now[ hash[u] ]; edge[len].v = hash[v]; now[ hash[u] ] = len++; } } } } void init(){ memset(old,-1,sizeof(int)*(n+1)); memset(tim,-1,sizeof(int)*(n+1)); memset(hash,-1,sizeof(int)*(n+1)); memset(hp,-1,sizeof(int)*(n+1)); memset(cost,-1,sizeof(int)*(n+1)); len = t = top = nn = sum = 0; minid=-1; } void build(){ int r,a,b; cin>>r; FF(i,r){ cin>>a>>b; edge[len].next=old[a]; edge[len].v=b; old[a]=len++; } } void d(int u){ checkmin(minid,id[u]); for(int i=now[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(s[v]>=9999999) d(v); } } int main() { while(cin>>n){ init(); int p,a,b; cin>>p; FF(i,p){ cin>>a>>b; cost[a]=b; } build(); Trajan(); FF(i,nn){ if(rudu[i]==0){ if(s[i]<9999999)sum+=s[i]; else d(i); } } if(minid!=-1)cout<<"NO"<<endl<<minid<<endl; else cout<<"YES"<<endl<<sum<<endl; } return 0; }