看是否存在一个环,使所有点都在此环内,并使权值最小。所有点在环内即父节点单一,所拆点建立二分图,只要最后通量为n,那么所有点就都能经过一遍,就符合上述情况。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> #include <queue> using namespace std; const int maxn=500; const int inf=0x3f3f3f3f; typedef long long ll; struct edge { int fr,to,c,f,cost; edge(int a,int b,int cc,int ff,int d):fr(a),to(b),c(cc),f(ff),cost(d) {} }; struct MCMF { int n; int m; int p[maxn],d[maxn],a[maxn]; int inq[maxn]; vector<edge> ee; vector<int> g[maxn]; void init(int n) { this->n=n; for(int i=0;i<=n;i++) g[i].clear(); ee.clear(); } void addage(int fr,int to,int c,int cost) { ee.push_back(edge(fr,to,c,0,cost)); ee.push_back(edge(to,fr,0,0,-cost)); m=ee.size(); g[fr].push_back(m-2); g[to].push_back(m-1); } bool spfa(int s,int t,int &flow,ll &cost) { memset(inq,0,sizeof(inq)); memset(d,inf,sizeof(d)); d[s]=0; p[s]=0; inq[s]=1; a[s]=inf; queue<int> q; q.push(s); while(q.size()) { int u=q.front(); q.pop(); inq[u]=0; for(int i=0;i<g[u].size();i++) { edge &nn=ee[g[u][i]]; if((nn.c>nn.f)&&(d[nn.to]>d[nn.fr]+nn.cost)) { d[nn.to]=d[nn.fr]+nn.cost; a[nn.to]=min(nn.c-nn.f,a[nn.fr]); p[nn.to]=g[u][i]; if(!inq[nn.to]) { q.push(nn.to); inq[nn.to]=1; } } } } if(d[t]==inf) return 0; flow+=a[t]; cost+=(ll)d[t]*(ll)a[t]; for(int i=t;i!=s;i=ee[p[i]].fr) { ee[p[i]].f+=a[t]; ee[p[i]^1].f-=a[t]; } return 1; } int mincostmaxflow(int s,int t,ll &cost) { int flow=0; cost=0; while(spfa(s,t,flow,cost)); return flow; } }zzz; int n; int main() { while(~scanf("%d",&n)&&n) { zzz.init(n+n+100); int s=2*n+1,t=2*n+2; for(int i=1;i<=n;i++) { zzz.addage(s,i,1,0); zzz.addage(n+i,t,1,0); } int a,b,z; for(int i=1;i<=n;i++) { while(~scanf("%d",&a)&&a) { scanf("%d",&b); zzz.addage(i,a+n,1,b); } } ll cost=0; int flow=zzz.mincostmaxflow(s,t,cost); if(flow==n) printf("%lld\n",cost); else printf("N\n"); } return 0; }