POJ 3436 拆点建图,第二道最大流

由于容量限制在点上,不是在边上,所以把一个点拆成两个点,一个是“入口”一个是“出口”,之间用点的容量建一条边...(这让我想到了关于空间维度的问题...= =||)

总结一下初级图论知识:

单源最短路 bell-fordman(用队列优化一下就是spfa,shortest path faster algorithm) 是可以用来找环的,一般是找负环,修改一下能找正环,时间分析:没加优化O(VE),加了优化O(KE)。

单源最短路 dijkstra,只能是正权边,采用贪心策略,加了一些限制的最短路或某些变形的最短路,最好还是用dijkstra,比如poj 1062 有个等级限制,就是一条路的中的边的等级差不能超过某个值, 还有poj2253求的是变形的最短路,要求每条路中的最大权值最小,除了这些变形最短路外,dijkstra还能求k短路,根据k值大小有两种方法,一种是保存多个值跑一次最短路,另一种是短边法...(k短路没做过题,不知道理解的对不对), 时间分析 不用堆优化O(n^2)

多源最短路径 Floyd,Floyd也能判断环(判断g[i][i]是否改变),Floyd还能求最小环的大小,时间分析o(n^3)

最小生成树:prim,kruskal,都是贪心策略,类似dijkstra

拓扑排序

二分图基数最大匹配(匈牙利算法)O(nm)

最大流 SAP  O(v^2 E)

下面是POJ3436代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<fstream>
using namespace std;
#define maxv 105
#define INF 0xfffffff
//ofstream fout("result.txt");
int n,pn,P,N;
int F[maxv][maxv];
int G[maxv][maxv];
int d[maxv];
int cnt[maxv];
int cur[maxv];
int p[maxv];
int exist(int u)
{
    int i;
    for(i=cur[u];i<=n;++i)
    {
        if(G[u][i]!=0&&d[u]==d[i]+1)
        {
            cur[u]=i;
//            fout<<"exist"<<endl;
            return i;
        }
    }
//    fout<<"not exist"<<endl;
    return -1;
}
void aug(int &f)
{
    int af=INF,i;
    for(i=0;i<pn-1;++i)
        af=min(af,G[p[i]][p[i+1]]);
    for(i=0;i<pn-1;++i)
    {
        G[p[i]][p[i+1]]-=af;
        G[p[i+1]][p[i]]+=af;
        F[p[i]][p[i+1]]+=af;
        F[p[i+1]][p[i]]=-F[p[i]][p[i+1]];
    }
    pn=0;
    f+=af;
//    fout<<"aug"<<endl;
    return ;
}
int renew(int u)
{
    cur[u]=1;
    int i,md=INF;
    bool flag=false;
    for(i=1;i<=n;++i)
    {
        if(G[u][i]!=0)
            md=min(md,d[i]),flag=true;
    }
    if(flag)
    {
        cnt[d[u]]--;
        if(cnt[d[u]]==0)
        {
//            fout<<"renew break"<<endl;
            return -1;
        }
        cnt[md+1]++;
        d[u]=md+1;
//        fout<<"renew"<<endl;
        return 1;
    }
    else
    {
//        fout<<"renew fail"<<endl;
        return 0;
    }
}
int SAP(int s,int t)
{
    pn=0;
    int f=0,i,j,flag;   
    memset(d,0,sizeof(d));
    memset(cnt,0,sizeof(cnt));
    memset(F,0,sizeof(F));
    cnt[0]=n;
    for(i=1;i<=n;++i)
        cur[i]=1;
    i=s;
//    fout<<"SAP pre end"<<endl;
    while(d[s]<n)
    {
        if((j=exist(i))!=-1)
        {
            p[pn++]=i;
            i=j;
            if(i==t)
            {
                p[pn++]=t;
                aug(f);
                i=s;
            }
        }
        else
        {
            flag=renew(i);
            if(flag==-1)
                return f;
            else if(flag==0)
                d[i]=n;
            if(i!=s)
                i=p[--pn];
        }
    }
//    fout<<"SAP end"<<endl;
    return f;
}
bool match(char* a,char *b)
{
    int i;
    for(i=0;i<P;++i)
    {
        if(b[i]=='2')
            continue;
        else if(a[i]!=b[i])
            return false;
    }
    return true;
}
int main()
{
//    ifstream fin("data.txt");
    int i,j,fm,to,cost,s,t,ans,cnt;
    char sm[]="0000000000";
    char em[]="1111111111";
    char in[55][15],out[55][15];
//    while(fin>>P>>N)
    while(cin>>P>>N)
    {
        n=2*N+2;
        memset(G,0,sizeof(G));
        for(i=1;i<=N;++i)
        {
//            fin>>cost;
            cin>>cost;
            for(j=0;j<P;++j)
//                fin>>in[i][j];
                cin>>in[i][j];
            for(j=0;j<P;++j)
//                fin>>out[i][j];
                cin>>out[i][j];
            if(match(sm,in[i]))
                G[2*N+1][i]=INF;
            if(match(out[i],em))
                G[i+N][2*N+2]=INF;
            G[i][i+N]=cost;
        }
//        fout<<"input compelete"<<endl;
        for(i=1;i<=N;++i)
        {
            for(j=i+1;j<=N;++j)
            {
                if(match(out[i],in[j]))
                {
                    G[i+N][j]=INF;
                }
                if(match(out[j],in[i]))
                {
                    G[j+N][i]=INF;
                }
            }
        }
        /*for(i=1;i<=N;++i)
        {
            for(j=i+1;j<=N;++j)
            {
                if(G[i+N][j]!=0)
                    cout<<i<<" "<<j<<endl;
                if(G[j+N][i]!=0)
                    cout<<j<<" "<<i<<endl;
            }
        }*/
//        fout<<"map constructed"<<endl;
        ans=SAP(2*N+1,2*N+2);
//        cout<<"SAP end"<<endl;
        cnt=0;
        for(i=1;i<=N;++i)
        {
            for(j=i+1;j<=N;++j)
            {
                if(F[i+N][j]>0)
                    cnt++;
                if(F[j+N][i]>0)
                    cnt++;
            }
        }
        cout<<ans<<" "<<cnt<<endl;
        for(i=1;i<=N;++i)
        {
            for(j=i+1;j<=N;++j)
            {
                if(F[i+N][j]>0)
                {
                    cout<<i<<" "<<j<<" "<<F[i+N][j]<<endl;
                }
                if(F[j+N][i]>0)
                {
                    cout<<j<<" "<<i<<" "<<F[j+N][i]<<endl;
                }
            }
        }
    }
//    system("pause");
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值