hdu1853/ hdu 3488 有向图,取k个圈覆盖所有点一次//费用流
哎╮(╯▽╰)╭,这是费用流基础题型,拆点,建二分图,跑最小费用最大流即可。若最大流为n,则说明是最大匹配为n,所有点都参与,每个点的入度和出度又是1,所以就是环。
弱菜还需努力!
#include<cstdio> #include<iostream> #include<queue> #include<cstring> using namespace std; const int inf=0x3f3f3f3f; int nume=0;int e[50000][4];int head[500]; int n,m; void inline adde(int i,int j,int c,int w) { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume][2]=c;e[nume++][3]=w; e[nume][0]=i;e[nume][1]=head[j];head[j]=nume; e[nume][2]=0;e[nume++][3]=-w; } int inq[500];int pre[500];int prv[500]; int d[500]; bool spfa(int &sum,int &sumflow) { for(int i=0;i<=2*n+2;i++) { inq[i]=0; d[i]=inf; } queue<int>q; q.push(0); inq[0]=1; d[0]=0; while(!q.empty()) { int cur=q.front(); q.pop(); inq[cur]=0; for(int i=head[cur];i!=-1;i=e[i][1]) { int v=e[i][0]; if(e[i][2]>0&&d[cur]+e[i][3]<d[v]) { d[v]=d[cur]+e[i][3]; pre[v]=i; prv[v]=cur; if(!inq[v]) { q.push(v); inq[v]=1; } } } } if(d[2*n+2]==inf)return 0; int cur=2*n+2;int minf=inf; while(cur!=0) { minf=e[pre[cur]][2]<minf?e[pre[cur]][2]:minf; cur=prv[cur]; } cur=2*n+2; while(cur!=0) { e[pre[cur]][2]-=minf; e[pre[cur]^1][2]+=minf; cur=prv[cur]; } sumflow+=minf; sum+=minf*d[2*n+2]; return 1; } int mincost(int &sumflow) { int sum=0; while(spfa(sum,sumflow)); return sum; } void init() { nume=0; memset(head,-1,sizeof(head)); } int main() { while(~scanf("%d%d",&n,&m)) { init(); int a,b,c; for(int i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c); adde(a,b+n,1,c); } for(int i=1;i<=n;i++) { adde(0,i,1,0); adde(i+n,2*n+1,1,0); } adde(2*n+1,2*n+2,n,0); int sumflow=0; int ans=mincost(sumflow); if(sumflow!=n) printf("-1\n"); else { printf("%d\n",ans); } } return 0; }