【BZOJ】【P2597】【Wc2007】【剪刀石头布】【题解】【费用流】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2597

wc的题不看题解能做? http://xietutu.com/archives/958

话说lrj的费用流模板常数真是一坨翔,好在氧气+linux+神评测机让我卡时过了

Code:

 
#include<bits/stdc++.h>
using namespace std;
const int maxn=20010;   
struct edge{int u,v,cap,flow,cost;};
vector<edge>edges;
vector<int>G[maxn];
void add(int u,int v,int cap,int cost){
    edges.push_back((edge){u,v,cap,0,cost});
    G[u].push_back(edges.size()-1);
    edges.push_back((edge){v,u,0,0,-cost});
    G[v].push_back(edges.size()-1);
}
int flow=0,cost=0,s,t,n;
int a[maxn],pre[maxn],d[maxn],in[maxn];
typedef pair<int,int> par;
#define fst first
#define sec second
par mp[maxn];
bool spfa(){
    static int vis[maxn];
    queue<int>q;
    memset(d,0x3f,sizeof d);int B=d[0];
    q.push(s);d[s]=0;a[s]=INT_MAX;
    while(!q.empty()){
        int u=q.front();q.pop();vis[u]=0;
        for(int i=0;i<G[u].size();i++){
            edge e=edges[G[u][i]];
            if(e.cap>e.flow&&d[e.v]>d[u]+e.cost){
                d[e.v]=d[u]+e.cost;
                pre[e.v]=G[u][i];
                a[e.v]=min(a[u],e.cap-e.flow);
                if(!vis[e.v]){
                    vis[e.v]=1;
                    q.push(e.v);
                }
            }
        }
    }if(d[t]==B)return false;
    flow+=a[t];cost+=d[t]*a[t];
    int u=t;
    while(u!=s){
        edges[pre[u]].flow+=a[t];
        edges[pre[u]^1].flow-=a[t];
        u=edges[pre[u]].u;
    }return true;
}
int main(){ 
    scanf("%d",&n);int m=n*(n-1)/2,cnt=0;
    s=0;t=n+m+1;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++){
        int x;
        scanf("%d",&x);
        if(j<=i)continue;
        cnt++;mp[cnt]=par(i,j);
        if(x==2)add(cnt,i+m,1,0),add(cnt,j+m,1,0),in[i]++,in[j]++;
        if(x==1)add(cnt,i+m,1,0),in[i]++;
        if(x==0)add(cnt,j+m,1,0),in[j]++;
    }for(int i=1;i<=m;i++)add(s,i,1,0);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=in[i];j++)
    add(i+m,t,1,2*j-1);
    while(spfa());
    cout<<(n*(n-1)*(n-2)/3+m-cost)/2<<endl;
    static int a[101][101],tot=0;
    for(int i=0;i<edges.size();i++)if(i%2==0){
        int u=edges[i].u,v=edges[i].v-m;
        if(u>=1&&u<=m&&v>=1&&v<=n&&edges[i].flow==1){
            a[mp[u].fst][mp[u].sec]=v==mp[u].fst;
            a[mp[u].sec][mp[u].fst]=v!=mp[u].fst;
        }
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    printf("%d%c",a[i][j]," \n"[j==n]);
    return 0;
}


你可能感兴趣的:(bzoj)