实际上就是先找出整个图里面的强连通分量,然后在每一个强连通子图里面,如果有可以受贿的罪犯,那么当前值就是最小的受贿的代价,否则就是INF, 然后在有向无环图中搞DP就好了。
#include <cstdio>
#include <algorithm>
#include <stack>
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN = 3000;
const int INF = 1000000000;
const int MAXM = 16000;
struct node{
int v;
node *next;
}Edges[MAXM+10], *adj[MAXN+10], *ecnt=Edges, *adj2[MAXN+10];
int kcnt, Min[MAXN+10], Minpeo[MAXN+10], Pid[MAXN+10], spend[MAXN+10], n;
stack<int> sta;
bool insta[MAXN+10];
vector<int> begin;
void addedge(int u, int v){
++ecnt;
ecnt->v = v;
ecnt->next = adj[u];
adj[u] = ecnt;
}
void addedge2(int u, int v){
++ecnt;
ecnt->v = v;
ecnt->next = adj2[u];
adj2[u] = ecnt;
}
int dfn[MAXN+10], low[MAXN+10], dcnt, tmp;
void dfs1(int u, int fa){
dfn[u] = low[u] = ++dcnt;
sta.push(u); insta[u] = true;
for(node *p=adj[u];p;p=p->next){
if(!dfn[p->v]){
dfs1(p->v, u);
low[u] = min(low[u], low[p->v]);
}else if(insta[p->v])
low[u] = min(low[u], dfn[p->v]);
}
if(dfn[u] == low[u]){
++kcnt;
Minpeo[kcnt] = INF; Min[kcnt] = INF;
do{
tmp = sta.top();
sta.pop();
Pid[tmp] = kcnt;
Min[kcnt] = min(Min[kcnt], spend[tmp]);
Minpeo[kcnt] = min(Minpeo[kcnt], tmp);
}while(tmp!=u);
}
insta[u] = false;
}
void prepare(){
for(int i=1;i<=n;i++)
if(!dfn[i])
dfs1(i, -1);
for(int i=1;i<=n;i++)
for(node *p=adj[i];p;p=p->next)
if(Pid[p->v] != Pid[i])
addedge2(Pid[i], Pid[p->v]);
}
void dfs2(int u, int _Min){
for(node *p=adj2[u];p;p=p->next){
if(Min[p->v] == INF)
dfs2(p->v, _Min);
Min[p->v] = 0;
}
}
void GetAns(){
//for(int i=1;i<=n;i++) printf("%d-%d\n", i, Pid[i]);
int Len = begin.size();//for(int i=1;i<=kcnt;i++) printf("%d\n", Min[i]);
for(int i=0;i<Len;i++)
dfs2(Pid[begin[i]], Min[Pid[begin[i]]]);
int Print = INF;
for(int i=1;i<=kcnt;i++)
if(Min[i] == INF)
Print = min(Print, Minpeo[i]);
if(Print != INF){
printf("NO\n%d\n", Print);
return ;
}
int sum = 0;
for(int i=1;i<=kcnt;i++)
sum += Min[i];
printf("YES\n%d\n", sum);
}
int main(){
scanf("%d", &n);
int r, id, pd;
scanf("%d", &r);
for(int i=1;i<=n;i++) spend[i] = INF;
for(int i=0;i<r;i++){
scanf("%d%d", &id, &pd);
spend[id] = pd;
begin.push_back(id);
}
scanf("%d", &r);
for(int i=0;i<r;i++){
scanf("%d%d", &id, &pd);
addedge(id, pd);
}
prepare();
GetAns();
return 0;
}