题意:从N个参赛选手中任选2人比赛,胜出的人将获得一定奖金b[i],每个人获胜的次数上限为c[i],给定a[i][j]矩阵,代表i与j需要比a[i][j]次.求要组织完这场赛事至少花费多少钱.赛事无法完成,输出"No,blablabla...".
构图:最小费用最大流,分别以比赛种类(所有i与j的比赛算一种)、参赛选手为两个集合构造二部图,
1.源点向比赛种类连费用为0,容量为a[i][j]的边;
2.参赛选手向汇点连费用为0,容量为获胜次数上限的边;
3.每种比赛分别向该种比赛(ivsj)的两个参赛选手i,j连费用为相应参赛选手获胜得到的奖金金额b[i]||b[j],容量为a[i][j]的边.
4.满流处理:只有比赛次数==胜出次数时,即只有胜出次数满流且等于比赛次数时,赛事才能完成,否则输出"No...".
注意:b[i]为单位次获胜得到的奖金,流量(flow)为获胜次数,总奖金为b[i]*flow.每次增广路操作后,执行ans+=dist[end]*flow计算总费用.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/*Source Code Problem: 1000 Username: 2010201211 Run Time: 268MS Memory: 856K Language:C++ JudgeStatus: Accepted */ #include <iostream> #include <stdio.h> #include <queue> #include <math.h> #include <string.h> using namespace std; #define V 400 #define E 65000 #define inf 999999999 #define infx 99999999999 int n,m,bs_cnt,sum; int vis[V]; long long dist[V]; int pre[V]; struct BS{ int x,y; }bs[V]; struct Edge{ int u,v,c,next; long long cost; }edge[E*2]; int head[V],cnt; void init(){ cnt=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int c,long long cost){ edge[cnt].u=u;edge[cnt].v=v;edge[cnt].cost=cost; edge[cnt].c=c;edge[cnt].next=head[u];head[u]=cnt++; edge[cnt].u=v;edge[cnt].v=u;edge[cnt].cost=-cost; edge[cnt].c=0;edge[cnt].next=head[v];head[v]=cnt++; } bool spfa(int begin,int end){ int u,v; queue<int> q; for(int i=0;i<=end+2;i++){ pre[i]=-1; vis[i]=0; dist[i]=infx; } vis[begin]=1; dist[begin]=0; q.push(begin); while(!q.empty()){ u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=edge[i].next){ if(edge[i].c>0){ v=edge[i].v; if(dist[v]>dist[u]+edge[i].cost){ dist[v]=dist[u]+edge[i].cost; pre[v]=i; if(!vis[v]){ vis[v]=true; q.push(v); } } } } } return dist[end]!=infx; } long long MCMF(int begin,int end){ long long ans=0; int flow; int flow_sum=0; while(spfa(begin,end)){ flow=inf; for(int i=pre[end];i!=-1;i=pre[edge[i].u]) if(edge[i].c<flow) flow=edge[i].c; for(int i=pre[end];i!=-1;i=pre[edge[i].u]){ edge[i].c-=flow; edge[i^1].c+=flow; } ans+=dist[end]*flow; //cout << ans << endl; flow_sum+=flow; //cout << flow_sum << endl; } if(flow_sum!=sum) return -1; else return ans; } int main() { //freopen("in.txt","r",stdin); int a[27][27],c[27]; long long b[27]; while(scanf("%d",&n)!=EOF){ for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin >> a[i][j]; for(int i=1;i<=n;i++) scanf("%lld",&b[i]); for(int i=1;i<=n;i++) cin >> c[i]; int z=0; sum=0; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++){ if(a[i][j]){ z++; bs[z].x=i; bs[z].y=j; sum+=a[i][j]; } } bs_cnt=z; init(); for(int i=1;i<=bs_cnt;i++) addedge(0,i,a[bs[i].x][bs[i].y],0); for(int i=bs_cnt+1;i<=bs_cnt+n;i++) addedge(i,bs_cnt+n+1,c[i-bs_cnt],0); for(int i=1;i<=bs_cnt;i++){ addedge(i,bs[i].x+bs_cnt,a[bs[i].x][bs[i].y],b[bs[i].x]); addedge(i,bs[i].y+bs_cnt,a[bs[i].x][bs[i].y],b[bs[i].y]); } long long res=MCMF(0,bs_cnt+n+1); if(res==-1) printf("No,that's worst!!\n"); else printf("%lld\n",res); } return 0; } /* Sample Input: 3 0 1 1 1 0 0 1 0 0 1 1 1 1 0 1 3 0 1 0 1 0 1 0 1 0 1 1 1 2 0 0 Sample Output: 2 No,that's worst!! */