题意:从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计算总费用.

View Code
/*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!!
*/