【网络流之最大流专题】解题报告

 

HDU 3572 Task Schedule

  这种题一开始完全想不出模型,题目做多了之后就有感觉了。

  对于这道题,求一次最大流,判断是否满流就可以了。

  建图:添加超级源点和汇点,对于每个任务,从源点向其连一条边,权值为Pi,因为要保证每个任务做够Pi天,然后把时限区间 si ~ ei 拆成一天一天的,那么该任务对应到一天连权值为1的边,最后,对于某一天,因为有m台机器可以同时工作,那么这一天向汇点连一条边,权值为m,求最大流。

/* HDU 3549 Flow Problem */
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         1e9
#define eps         1e-6
#define MAXN        1005
#define MAXM        1000005
#define MODN        1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];   
int head[MAXN], NE; 

int n, m;
int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];

void add_edge (int u, int v, int w)
{
    E[NE].v = v;   
    E[NE].w = w;
    E[NE].next = head[u];
    head[u] = NE++;
    
    E[NE].v = u;
    E[NE].w = 0;
    E[NE].next = head[v];
    head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<n;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=n;
    while(dis[s]<n)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=n;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

int main()
{
    int p, s, e;
    int t, sum;
    int cas = 1;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        init();
        sum = 0;
        int l = inf, r = -1;
        rep(i,1,n)
        {
            RIII(p, s, e);
            add_edge(0,i,p);
            sum += p;
            l = min(l, s);
            r = max(r, e);
            rep(j,s+n,e+n)
                add_edge(i, j, 1);
        }
        
        int des = 1 + r + n;
        rep(i,1,r)
            add_edge(i+n,des,m);
        n = des + 1;
        int ans = sap(0, des);
        printf("Case %d: %s\n\n", cas++, ans == sum ? "Yes" : "No");
    }
    return 0;
}
View Code

 

HDU 2883 kebab

  这一题和上一题很相似,只不过 si 和 ei 的范围很大,把范围拆成一天一天很不划算。那好,既然这样,我们就拆成一个个小的区间吧,相当于把点铺在数轴上,分别取[si,ei]包含的小区间[a,b]连权值为(b-a)*M的边,当然源点汇点的建立和上一题差不多的,最后依然是判满流。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        1005
#define MAXM        8000005
#define MODN        1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

struct Seg
{
    int s, t;
}A[MAXN], B[MAXN];

int head[MAXN], NE; 
int n, m, N;
int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];

void add_edge (int u, int v, int w)
{
    E[NE].v = v;   
    E[NE].w = w;
    E[NE].next = head[u];
    head[u] = NE++;
    
    E[NE].v = u;
    E[NE].w = 0;
    E[NE].next = head[v];
    head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

int L[MAXN];

int main()
{
    int si, ni, ei, ti, k, s, t, sum;
    while(RII(n,m) != EOF)
    {
        init();
        s = 0, t = 3*n;
        sum = 0; k = 0;
        rep(i,1,n)
        {
            scanf("%d%d%d%d", &si, &ni, &ei, &ti);
            A[i].s = si, A[i].t = ei;
            add_edge(s,i,ni*ti);
            sum += ni*ti;
            L[++k] = si;
            L[++k] = ei;
        }
        sort(L+1, L+k+1);
        rep(i,1,k-1)
        {
            B[i].s = L[i];
            B[i].t = L[i+1];
            add_edge(n+i, t, (B[i].t - B[i].s) * m);
        }
        rep(i,1,n)
            rep(j,1,k-1)
                if(A[i].s <= B[j].s && A[i].t >= B[j].t)
                    add_edge(i, n+j, inf);
                    
        N = t + 1;
        int ans = sap(s, t);
        printf("%s\n", ans == sum ? "Yes" : "No");
    }
    return 0;
}
View Code

 

HDU 3605 Escape

  首先看到 n <= 100000,就知道普通的人与星球建边方法会TLE,这题m最多只有10,那么所有人的对应状态最多只有1024个,那么nn <= 100000里面会出现很多重复状态的人,那么我们可以把人的状态进行压缩、统计,之后就是从状态到星球直接连边建图判满流了。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        100015
#define MAXM        4000005
#define MODN        1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

int head[MAXN], NE; 
int n, m, N;
int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];
int num[MAXN];

void add_edge (int u, int v, int w)
{
    E[NE].v = v;   
    E[NE].w = w;
    E[NE].next = head[u];
    head[u] = NE++;
    
    E[NE].v = u;
    E[NE].w = 0;
    E[NE].next = head[v];
    head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0; clr(num);
    memset(head, -1, sizeof head);
}

int main()
{
    int c, cnt;
    while(RII(n, m) != EOF)
    {
        init();
        cnt = 0;
        rep(i,1,n)
        {
            int x = 0;
            rep(j,1,m)
            {
                RI(c);
                x = (x << 1) | c;
            }
            if(!num[x]) cnt++;
            num[x]++;
        }
        int k = cnt;
        int t = 1+k+m;
        rep(i,1,m)
        {
            RI(c);
            add_edge(cnt+i,t,c);
        }
        cnt = 0;
        rep(i,0,1024)
        {
            if(!num[i]) continue;
            add_edge(0, ++cnt, num[i]);
            rep(j,1,m)
            {
                if((i>>(j-1))&1)
                    add_edge(cnt, k+j, num[i]);
            }
        }
        N = t+1;
        int ans = sap(0, t);
        if(ans == n)
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}
View Code

 

HDU 4183 Pahom on Water

  由于除了起点和终点外,其他的结点在访问一次之后就不可再利用了,对于这种情况,不难想到要对每个结点进行拆点,在拆成的连点之间连一条容量为1的边i->i',就可以保证只访问一次(这种化点为边的思想在网络流里很重要),题目要求从起点到终点再从终点到起点的过程可以转化为判断能否从起点开始,有两条不重复的路径到达终点,显然,超级源点到起点间连一条容量为2的边s->i,然后从终点拆点到汇点也连一条容量为2的边i'->t,中间可以跳跃的点之间连容量>=1的边i'->j,最后求最大流看是否满流。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        1005
#define MAXM        1000005
#define MOD         1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

struct Node
{
    double Mz;
    int x, y, r;
}A[MAXN];

int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int n, m, N;
int head[MAXN], NE;
bool g[MAXN][MAXN];

void add_edge (int u, int v, int w)
{
    E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++;
    E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0; clr(g);
    memset(head, -1, sizeof head);
}

double dist(Node q, Node p)
{
    return (q.x - p.x) * (q.x - p.x) + (q.y - p.y) * (q.y - p.y);
}

int main()
{
    int cas, s, t;
    double a;
    int b, c, d;
    RI(cas);
    while(cas--)
    {
        RI(n);
        init();
        s = 2 * n + 1, t = 2 * n + 2;
        rep(i,1,n)
        {
            scanf("%lf%d%d%d", &a, &b, &c, &d);
            A[i].Mz = a, A[i].x = b, A[i].y = c, A[i].r = d;
        }
        for(int i = 1; i <= n; i++)
        {
            add_edge(i, i+n, 1);
            
            for(int j = 1; j<=n; j++)
                if(A[i].Mz < A[j].Mz && dist(A[i], A[j]) < (A[i].r + A[j].r) * (A[i].r + A[j].r))
                    add_edge(i+n, j, 1);
            
            if(A[i].Mz == 400.0)
                add_edge(s, i+n, 2);
            else if(A[i].Mz == 789.0)
                add_edge(i, t, 2);
        }
        N = 2 + n*2;
        int ans = sap(s, t);
        if(ans < 2)
            puts("Game is NOT VALID");
        else
            puts("Game is VALID");
    }
    return 0;
}
View Code

 

HDU 4240 Route Redundancy

  这道题题意很明确,二分最短路+最大流,属于简单题。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        1005
#define MAXM        200005
#define MOD         1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM], E1[MAXM];      // edge list

int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int n, m;
int head[MAXN], NE;
int d[MAXN];
bool vis[MAXN];

void addedge (int u, int v, int w)
{
    E[NE].v = v;   
    E[NE].w = w;
    E[NE].next = head[u];
    head[u] = NE++;
    
    E[NE].v = u;
    E[NE].w = 0;
    E[NE].next = head[v];
    head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<n;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=n;
    while(dis[s]<n)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=n;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void spfa(int s, int val)
{
    queue<int> que;
    memset(d, 0x3f, sizeof d);
    memset(vis, false, sizeof vis);
    d[s] = 0;
    vis[s] = true;
    que.push(s);
    while(!que.empty())
    {
        int u = que.front();
        que.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = E1[i].next)
        {
            int nx = E1[i].v;
            int cost = E1[i].w;
            if(d[u] + cost < d[nx] && cost >= val)
            {
                d[nx] = d[u] + cost;
                if(!vis[nx])
                {
                    vis[nx] = true;
                    que.push(nx);
                }
            }
        }
    }
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

int main()
{
    int cas, s, t, id;
    int u, v, w;
    RI(cas);
    while(cas--)
    {
        scanf("%d%d%d%d%d", &id, &n, &m, &s, &t);
        init();
        int l = inf, r = -1;
        rep(i,1,m)
        {
            RIII(u, v, w);
            addedge(u, v, w);
            r = max(r, w);
            l = min(l, w);
        }
        memcpy(E1, E, sizeof E);
        int maxflow = sap(s, t);
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            spfa(s, mid);
            if(d[t] < inf)
                l = mid + 1;
            else
                r = mid - 1;
        }
        printf("%d %.3lf\n", id, maxflow*1.0/(l-1));
    }
    return 0;
}
View Code

 

HDU 3081 Marriage Match II

  二分最大流。

  建边的时候用到并查集,因为女孩会根据她的女性朋友和男孩之间的是否吵过架连边。超级源点和女孩之间连边,权值为二分值;男孩和超级汇点之间连边,权值也是二分值,二分判断最大流是否满流即可。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        505
#define MAXM        1000005
#define MOD         1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

struct Node
{
    int x, y;
}a[MAXM];

int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int n, m, N;
int head[MAXN], NE;
int f[MAXN];
bool g[MAXN][MAXN];

void add_edge (int u, int v, int w)
{
    E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++;
    E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0; clr(g);
    memset(head, -1, sizeof head);
}

int find(int x)
{
    return f[x] == x ? f[x] : f[x] = find(f[x]);
}

void union_set(int u, int v)
{
    int x = find(u);
    int y = find(v);
    f[x] = y;
}

void build(int s, int t, int v)
{
    init();
    rep(i,1,n)
    {
        add_edge(s, i, v);
        add_edge(n+i, t, v);
    }
    rep(i,1,m)
    {
        rep(j,1,n)
        {
            if(find(j) == find(a[i].x) && !g[j][a[i].y])
            {
                g[j][a[i].y] = true;
                add_edge(j, n+a[i].y, 1);
            }
                
        }
    }
}

int main()
{
    int cas, s, t, F, u, v;
    RI(cas);
    while(cas--)
    {
        RIII(n, m, F);
        s = 0, t = 2*n+1;
        rep(i,0,n) f[i] = i;
        rep(i,1,m)
            RII(a[i].x, a[i].y);
        rep(i,1,F)
        {
            RII(u, v);
            union_set(u, v);
        }
        N = t+1;
        int l = 0, r = n;
        int ans = 0;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            build(s, t, mid);
            if(sap(s,t) == n * mid)
            {
                ans = mid;
                l = mid + 1;
            }
            else
                r = mid - 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

HDU 3277 Marriage Match III

  这道题和上一道题HDU 3081一样都是二分最大流,这题多了一点“ in order to play more times of marriage match, every girl can accept any K boys”,解决这个问题的做法是把女孩进行拆点,边权为K。对于某个女孩,和吵过架的男孩连一条边i'->j,权值为1。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        1005
#define MAXM        5000005
#define MOD         1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

struct Node
{
    int x, y;
}a[MAXM];

int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int n, m, k, N;
int head[MAXN], NE;
int f[MAXN];
bool g[MAXN][MAXN];
int low;

void add_edge (int u, int v, int w)
{
    E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++;
    E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    clr(dis); clr(gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

int find(int x)
{
    return f[x] == x ? f[x] : f[x] = find(f[x]);
}

void union_set(int u, int v)
{
    int x = find(u);
    int y = find(v);
    f[x] = y;
}

void build(int s, int t, int v)
{
    init();
    rep(i,1,n)
    {
        add_edge(s, i, v);
        add_edge(2*n+i, t, v);
    }
    rep(i,1,n)
        add_edge(i, i+n, k);
        
    rep(i,1,n)
    {
        rep(j,1,n)
        {
            if(g[i][j])
                add_edge(i, 2*n+j, 1);
            else
                add_edge(i+n, 2*n+j, 1);
        }
    }
}

int main()
{
    int cas, s, t, F, u, v;
    RI(cas);
    while(cas--) 
    {
        scanf("%d%d%d%d", &n, &m, &k, &F);
        s = 0, t = 3*n+1;
        rep(i,0,n) f[i] = i;
        rep(i,1,m)
            RII(a[i].x, a[i].y);
        rep(i,1,F)
        {
            RII(u, v);
            union_set(u, v);
        }
        clr(g);
        rep(i,1,m)
            g[find(a[i].x)][a[i].y] = true;
        rep(i,1,n)
            rep(j,1,n)
                if(g[find(i)][j])
                    g[i][j] = true;
        N = t+1;
        int l = 0, r = n;
        int ans = 0;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            build(s, t, mid);
            if(sap(s, t) == n * mid)
            {
                ans = mid;
                l = mid + 1;
            }
            else
                r = mid - 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

HDU 2485 Destroying the bus stations

  这道题很明显用最小费用最大流。

  拆点后,每一次求最短路可以除掉一条边,也就是去掉一个station,一直求最短路直到大于K为止,所统计的流量就是所求。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <queue>
#include <cassert>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         (0x3f3f3f3f)
#define eps         1e-6
#define MAXN        1005
#define MAXM        4000005
#define MODN        1000000007
#define RI(x)       scanf("%d", &x)
#define RII(x,y)    scanf("%d%d", &x, &y)
#define RIII(x,y,z) scanf("%d%d%d", &x, &y, &z)
#define debug       puts("reach here");
typedef long long LL;

struct Edge
{
    int to;
    int vol;
    int cost;
    int next;
}E[MAXM];

int index[MAXN];
int NE;
int pre[MAXN], pos[MAXN];
int dis[MAXN], que[MAXM];
bool vis[MAXN];
int n, m, k;

void insert(int from, int to, int vol, int cost)
{
    E[NE].to = to;   E[NE].vol = vol; E[NE].cost = cost;  E[NE].next = index[from]; index[from] = NE++;
    E[NE].to = from; E[NE].vol = 0;   E[NE].cost = -cost; E[NE].next = index[to];   index[to] = NE++;
}

bool spfa(int s, int t)
{
    memset(pre, -1, sizeof(pre));
    memset(vis, 0, sizeof(vis));
    int head, tail; head = tail = 0;
    memset(dis, 0x3f, sizeof dis);
    que[tail++] = s;
    pre[s] = s;
    dis[s] = 0;
    vis[s] = 1;
    while(head != tail)
    {
        int cur = que[head++];
        vis[cur] = 0;
        for(int i = index[cur]; i != -1; i = E[i].next)
        {
            int adj = E[i].to;
            if(E[i].vol > 0 && dis[cur] + E[i].cost < dis[adj])
            {
                dis[adj] = dis[cur] + E[i].cost;
                pre[adj] = cur;
                pos[adj] = i;
                if(!vis[adj])
                {
                    vis[adj] = 1;
                    que[tail++] = adj;
                }
            }
        }
    }
    return pre[t] != -1;
}

int MinCostMaxFlow(int s, int t)
{
    int cost = 0; 
    int flow = 0;  
    while(spfa(s, t))
    {
        if(dis[t] > k) return flow;   
        int f = inf;
        for(int i = t; i != s; i = pre[i])
            if (E[pos[i]].vol < f) f = E[pos[i]].vol;
        flow += f; cost += dis[t] * f;
        for(int i = t; i != s; i = pre[i])
        {
            E[pos[i]].vol -= f;
            E[pos[i] ^ 1].vol += f;
        }
    }
    return flow; 
}

void init()
{
    NE = 0;
    memset(index, -1, sizeof index);
}

int main()
{
    int a, b;
    while(RIII(n, m, k) != EOF)
    {
        if(n==0 && m==0 && k==0) break;
        init();
        rep(i,0,n-1)
            insert(i<<1, i<<1|1, 1, 0);
        rep(i,0,m-1)
        {
            RII(a, b);
            a--, b--;
            insert(a<<1|1, b<<1, 1, 1);
        }
        printf("%d\n", MinCostMaxFlow(1, (n-1)<<1));
    }
}
View Code

 

HDU 3468 Treasure Hunting

  一开始没看出来是网络流,一直往搜索的思路想。

  题意理解也略微蛋疼,这个解题报告写得不错。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        20005
#define MAXM        5000005
#define MOD         1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

struct Node 
{
    int x, y, cnt;
};

int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int n, m, N, k, c;
int head[MAXN], NE;
char g[101][101];
int dr[4][2] = {{0,1}, {0,-1}, {1,0}, {-1, 0}};
int d[55][MAXN];
int tot; 
int to[55];

void add_edge (int u, int v, int w)
{
    E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++;
    E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

bool isOut(int xx, int yy)
{
    return !(xx >= 0 && xx < m && yy >= 0 && yy < n);
}

int getID(char c)
{
    return islower(c) ? c - 'a' + 26 : c-'A';
}

void getRalCnt()
{
    tot = 0;
    rep(i,0,n-1)
    {
        rep(j,0,m-1)
        {
            if(isalpha(g[i][j]))
                tot++;
        }
    }
}

bool bfs(int y, int x, int id)
{
    queue<Node> que;
    Node tmp;
    int cnt = 1;
    tmp.x = x, tmp.y = y, tmp.cnt = 0;
    que.push(tmp);
    d[id][y*m+x] = 0;
    while(!que.empty())
    {
        Node cur = que.front();
        que.pop();
        int cx = cur.x;
        int cy = cur.y;
        int cc = cur.cnt;
        rep(i,0,3)
        {
            int xx = cx + dr[i][0];
            int yy = cy + dr[i][1];
            if(!isOut(xx,yy) && g[yy][xx] != '#' && d[id][yy*m+xx] == -1)
            {
                tmp.x = xx, tmp.y = yy, tmp.cnt = cc +  1;
                d[id][yy*m+xx] = cc + 1;
                que.push(tmp);
                if(isalpha(g[yy][xx]))
                {
                    cnt++;
                    if(getID(g[yy][xx]) == id + 1)
                        to[id] = cc + 1;
                }
            }
        }
    }
    return cnt == tot;
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

void build()
{
    int goldCnt = tot+1;
    init();
    rep(i,0,n-1)
    {
        rep(j,0,m-1)
        {
            if(g[i][j] == '*')
            {
                rep(k,0,tot-2)
                {
                    if(d[k][i*m+j] + d[k+1][i*m+j] == to[k])
                        add_edge(k+1, goldCnt, 1);
                }
            }
            goldCnt++;
        }
    }
    rep(i,1,tot-1)
        add_edge(0, i, 1);
    rep(i,tot+1,goldCnt-1)
        add_edge(i, tot, 1);
    N = goldCnt;
}

bool calDis()
{
    memset(d, -1, sizeof d);
    getRalCnt();
    rep(i,0,n-1)
        rep(j,0,m-1)
            if(isalpha(g[i][j])) 
                 if(!bfs(i,j,getID(g[i][j])))
                    return false;
    return true;
}

int main()
{
    while(RII(n, m) != EOF)
    {
        rep(i,0,n-1)
            scanf("%s", g[i]);
        if(!calDis())
        {
            puts("-1");
            continue;
        }
        build();
        printf("%d\n", sap(0, tot));
    }
    return 0;
}
View Code

 

HDU 4309 Seikimatsu Occult Tonneru

  因为桥最多有12条,所以直接2^12枚举修复的桥。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        1005
#define MAXM        5000005
#define MOD         1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

struct Node
{
    int a, b, c, d;
}A[MAXM];

int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int n, m, k, N;
int head[MAXN], NE;
int num[MAXN];
int cid[MAXM], cnt;
bool vis[MAXN];

void add_edge (int u, int v, int w)
{
    E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++;
    E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    clr(dis); clr(gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

int main()
{
    int tot;
    while(RII(n, m) != EOF)
    {
        int s = 0, t = n+1;
        init();
        cnt = 0;
        tot = 0;
        memset(cid, -1, sizeof cid);
        rep(i,1,n)
        {
            RI(num[i]);
            add_edge(s, i, num[i]);
        }
        rep(i,1,m)
        {
            scanf("%d%d%d%d", &A[i].a, &A[i].b, &A[i].c, &A[i].d);
            if(A[i].d > 0)
            {
                cid[i] = cnt++;
                tot += A[i].c;
            }
                
            if(A[i].d < 0)
                add_edge(A[i].a, t, A[i].c);
                
            add_edge(A[i].a, A[i].b, inf);
        }
        N = n + 2;
        int maxFlow = sap(s, t);
        if(maxFlow == 0)
        {
            puts("Poor Heaven Empire");
            continue;
        }
        //printf("%d\n", ans);
        int cost;
        int ans = tot;
        rep(i,0,(1<<cnt)-1)
        {
            init();
            cost = 0;
            rep(j,1,n)
                add_edge(s, j, num[j]);
            rep(j,1,m)
            {
                if(cid[j] >= 0)
                {
                    if(i & (1 << cid[j])) // fix the road
                    {
                        add_edge(A[j].a, A[j].b, inf);
                        cost += A[j].c;
                    }
                    else                  // not fix
                        add_edge(A[j].a, A[j].b, 1);
                }
                else
                {
                    if(A[j].d < 0)
                        add_edge(A[j].a, t, A[j].c);
                    add_edge(A[j].a, A[j].b, inf);
                }
            }
            int tmp = sap(s, t);
            if(tmp == maxFlow)
                ans = min(ans, cost);
        }
        printf("%d %d\n", maxFlow, ans);
    }
    return 0;
}
View Code

 

POJ 3281 Dining

  很不错的一道题,对牛进行拆点,容量为1,建图顺序为:超级源点 -> 食物 -> 牛 -> 饮料 -> 超级汇点,这样想通之后应该就不难做了。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         1e9
#define eps         1e-6
#define MAXN        505
#define MAXM        10000005
#define MODN        1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];      
int head[MAXN], NE;  

int n, m, k, N;
int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];

void add_edge (int u, int v, int w)
{
    E[NE].v = v;   
    E[NE].w = w;
    E[NE].next = head[u];
    head[u] = NE++;
    E[NE].v = u;
    E[NE].w = 0;
    E[NE].next = head[v];
    head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

int main()
{
    int f, d, a, b, s, t, k1, k2;
    while(RIII(n,f,d) != EOF)
    {
        init();
        s = 0, t = f + d + 2*n + 1;
        rep(i,1,f)
            add_edge(s, i, 1);
        rep(i,1,d)
            add_edge(f+2*n+i, t, 1);
        rep(i,f+1, f+n)
            add_edge(i,i+n,1);
        rep(i,1,n)
        {
            RII(k1,k2);
            rep(x,1,k1)
            {
                RI(a);
                add_edge(a, f+i, 1);
            }
            rep(x,1,k2)
            {
                RI(b);
                add_edge(f+n+i, f+2*n+b,1);
            }
        }
        N = t+1;
        printf("%d\n", sap(s, t));
    }
    return 0;
}
View Code

 

POJ 2112 Optimal Milking

  floyd求一下最短路,然后二分距离建图求最大流,判断是否满流。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        505
#define MAXM        1000005
#define MOD         1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int n, m, N, k, c;
int head[MAXN], NE;
int d[MAXN][MAXN];

void add_edge (int u, int v, int w)
{
    E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++;
    E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

void build(int v)
{
    init();
    int s = 0, t = k + c + 1;
    rep(i,1,c)
        add_edge(s, k+i, 1);
    rep(i,1,k)
        add_edge(i, t, m);
    rep(i,k+1,k+c)
        rep(j,1,k)
            if(d[i][j] <= v)
                add_edge(i, j, 1);
}

int main()
{
    int maxd;
    while(RIII(k,c,m) != EOF)    
    {
        maxd = 0;
        rep(i,1,k+c)
            rep(j,1,k+c)
            {
                RI(d[i][j]);
                if(d[i][j] == 0) d[i][j] = inf;
            }
        rep(p,1,k+c)
            rep(i,1,k+c)
                rep(j,1,k+c)
                    d[i][j] = min(d[i][j], d[i][p] + d[p][j]);
        rep(i,1,k+c)
            rep(j,1,k+c)
                if(d[i][j] < inf)
                    maxd = max(maxd, d[i][j]);
            
        int l = 0, r = maxd;
        N = k+c + 2;
        int ans = 0;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            build(mid);
            if(sap(0, k+c+1) == c)
            {
                r = mid - 1;
                ans = mid;
            }
            else
                l = mid + 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

POJ 2289 Jamie's Contact Groups

  还是二分最大流。不说了,说多了都是泪。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        2005
#define MAXM        5000005
#define MOD         1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int n, m, N, k, c;
int head[MAXN], NE;
bool g[MAXN][MAXN];

void add_edge (int u, int v, int w)
{
    E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++;
    E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

void build(int s, int t, int v)
{
    init();
    rep(i,1,n)
        add_edge(s, i, 1);
    rep(i,1,n)
        rep(j,n+1,n+m)
            if(g[i][j])
                add_edge(i,j,1);
    rep(i,n+1,n+m)
        add_edge(i,t,v);
}

int main()
{
    char s[20];
    int a;
    while(RII(n, m) != EOF)
    {
        if(n == 0 && m == 0) break;
        clr(g);
        rep(i,1,n)
        {
            scanf("%s", s);
            while(getchar() == ' ')
            {
                scanf("%d", &a);
                g[i][n+1+a] = true;
            }
        }
        N = 2 + n + m;
        int src = 0, des = N-1;
        int l = 0, r = n;
        int ans = 0;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            build(src, des, mid);
            if(sap(src, des) == n)
            {
                r = mid - 1;
                ans = mid;
            }
            else
                l = mid + 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

POJ 3498 March of the Penguins

  枚举终点,每个点i拆点,边容量为mi,超级源点连一条边到每个点,容量分别为ni,对于可以相互跳跃到达的顶点,连一条边i'->j,容量为无穷大,统计一共有多少个点作为终点可以满流。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        205
#define MAXM        500005
#define MOD         1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

struct Node
{
    double x, y;
    int ni,mi;
}a[MAXN];

int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int n, m, N;
int head[MAXN], NE;
double D;
bool g[101][101];

void add_edge (int u, int v, int w)
{
    E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++;
    E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

int ans[105];

void build(int s, int t, int id)
{
    init();
    rep(i,0,n-1)
    {
        add_edge(i, i+n, a[i].mi);
        add_edge(s, i, a[i].ni);
    }
    rep(i,0,n-1)
    {
        rep(j,0,n-1)
        {
            if(i == j) continue;
            if(g[i][j])
                add_edge(i+n, j, inf);
        }
    }
}

int main()
{
    int cas, sum;
    RI(cas);
    while(cas--)
    {
        scanf("%d%lf", &n, &D);
        sum = 0;
        rep(i,0,n-1)
        {
            scanf("%lf%lf%d%d", &a[i].x, &a[i].y, &a[i].ni, &a[i].mi);
            sum += a[i].ni;
        }
        clr(g);
        rep(i,0,n-1)
        {
            rep(j,0,n-1)
            {
                if(D * D >= (a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y))
                    g[i][j] = true;
            }
        }
        int cnt = 0;
        int s =  2*n, t = 2*n+1;
        N = 2*n + 2;
        rep(i,0,n-1)
        {
            build(s, i, i);
            if(sap(s, i) == sum)
                ans[cnt++] = i;
        }
        if(cnt == 0)
            puts("-1");
        else
        {
            rep(i,0,cnt-1)
                printf("%d%c", ans[i], i == cnt-1 ? '\n' : ' ');
        }
    }
    return 0;
}
View Code

 

POJ 3228 Gold Transportation

  题目要求在满流的情况下的一个最长路径最短的方案,明显二分最大流。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         0x3f3f3f3f
#define eps         1e-6
#define MAXN        505
#define MAXM        1000005
#define MOD         1000000007
#define debug       puts("reach here")
#define MP          make_pair
#define PB          push_back
#define RI(x)       scanf("%d",&x)
#define RII(x,y)    scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL;

struct Edge
{
    int v, w, next;
}E[MAXM];     

struct Node
{
    int u, v, w;
}e[MAXM];

int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int n, m, N;
int head[MAXN], NE;

void add_edge (int u, int v, int w)
{
    E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++;
    E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++;
}

inline void checkmin(int &a,int b)  {if(a == -1 || a > b)a = b;}

int sap(int s,int t)
{
    memset(dis,0,sizeof dis);
    memset(gap,0,sizeof gap);
    for(int i=0;i<N;++i) cur[i]=head[i];
    int u=pre[s]=s,maxflow=0,aug=-1;
    gap[0]=N;
    while(dis[s]<N)
    {
loop:for(int &i=cur[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && dis[u]==dis[v]+1)
            {
                checkmin(aug,E[i].w);
                pre[v]=u;
                u=v;
                if(v==t)
                {
                    maxflow+=aug;
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        E[cur[u]].w-=aug;
                        E[cur[u]^1].w+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int mindis=N;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(E[i].w && mindis>dis[v])
            {
                cur[u]=i;
                mindis=dis[v];
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return maxflow;
}

void init()
{
    NE = 0;
    memset(head, -1, sizeof head);
}

int a[MAXN], b[MAXN];


void build(int s, int t, int v)
{
    init();
    rep(i,1,n)
    {
        add_edge(s, i, a[i]);
        add_edge(i, t, b[i]);
    }
    
    rep(i,1,m)
        if(e[i].w <= v)
        {
            add_edge(e[i].u, e[i].v, inf);
            add_edge(e[i].v, e[i].u, inf);
        }
}

int main()
{
    int sum;
    while(RI(n) != EOF && n)
    {
        rep(i,1,n)
            RI(a[i]);
        rep(i,1,n)
            RI(b[i]);
        sum = 0;
        rep(i,1,n)
            sum += a[i];
        RI(m);
        rep(i,1,m)
        {
            RIII(e[i].u, e[i].v, e[i].w);
        }
        int l = 0, r = 10001;
        N = n + 2;
        int ans = -1;
        int s = 0, t = n + 1;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            build(s, t, mid);
            if(sap(s, t) == sum)
            {
                r = mid - 1;
                ans = mid;
            }
            else
                l = mid + 1;
        }
        if(ans == -1)
            puts("No Solution");
        else
            printf("%d\n", ans);
    }
    return 0;
}
View Code

 

 

posted @ 2013-09-05 23:29  芒果布丁  阅读(394)  评论(0编辑  收藏  举报