恰好属于一个圈,那等价与每个点有唯一的前驱和后继,这让人想到了二分图,
把一个点拆开,点的前驱作为S集和点的后继作为T集,然后连边,跑二分图最小权完美匹配。
写的费用流。。最大权完美匹配KM算法没看懂
#include<bits/stdc++.h> using namespace std; const int maxn = 200+6; struct Edge { int v,cap,cost,nxt; }; vector<Edge> edges; #define PB push_back int head[maxn]; void addEdge(int u,int v,int C,int c) { edges.PB(Edge{v,C,c,head[u]}); head[u] = edges.size()-1; } void AddEdge(int u,int v,int C,int c) { addEdge(u,v,C,c); addEdge(v,u,0,-c); } typedef int ll; int S = 0,T = 1,vcnt; int d[maxn],p[maxn],a[maxn]; bool vis[maxn]; const int INF = 0x3f3f3f3f; ll MCMF(ll &cost) { cost = 0; ll flow = 0; while(true){ memset(vis,0,sizeof(bool)*vcnt); memset(d,0x3f,sizeof(int)*vcnt); queue<int> q; q.push(S); d[S] = 0; a[S] = INF; while(q.size()){ int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; ~i; i = edges[i].nxt){ Edge &e = edges[i]; if(e.cap && d[e.v] > d[u]+e.cost){ d[e.v] = d[u] + e.cost; p[e.v] = i; a[e.v] = min(e.cap,a[u]); if(!vis[e.v]){ vis[e.v] = true; q.push(e.v); } } } } if(d[T] == INF) return flow; flow += a[T]; cost += a[T]*d[T]; for(int i = T; i != S; i = edges[p[i]^1].v){ edges[p[i]].cap -= a[T]; edges[p[i]^1].cap += a[T]; } } return -1; } void init() { memset(head,-1,sizeof(int)*vcnt); edges.clear(); } int main() { //freopen("in.txt","r",stdin); int n; S = 0; while(scanf("%d",&n),n){ vcnt = 2*n+2; init(); T = 2*n+1; for(int i = 1; i <= n; i++){ AddEdge(S,i,1,0); AddEdge(i+n,T,1,0); } for(int i = 1; i <= n; i++){ int v,c; while(scanf("%d",&v),v){ scanf("%d",&c); AddEdge(i,v+n,1,c); } } int cost; int flow = MCMF(cost); if(flow<n) puts("N"); else printf("%d ",cost); } return 0; }