UVA 563 最大流

很显然就是一个最大流题目。

不过进行建模不好想

需要用到一个拆点操作,所谓拆点就是将一个点转化为一条边,中间流量是1

建立超级源点跟超级汇点。

源点跟银行相连接,图的边界点跟汇点相连接。

从而套用模板计算最大流即可,但令我困惑的是自己的模板好像写错了,但是不应该呀,过了别的题了呀,难道是因为那几道题目数据量太弱吗?很不理解,最后套用别人模板给AC了:

Dinic

#include <iostream>
#include <string.h>
#include <queue>
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAX_N=10000;     //顶点数上限
const int MAX_M=500000;    //总的边数上限

struct edge{
    int v,c,next;       //v指另一个顶点,c表示容量。
}e[MAX_M];

int p[MAX_N],eid;
int n,m;
int S,T;                             //S是源点,T是汇点。

int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};

void insert(int u,int v,int c){ //插入一条从u向v,容量为c的弧。
    e[eid].v=v;
    e[eid].next=p[u];
    e[eid].c=c;
    p[u]=eid++;
}

void addedge(int u,int v,int c){ //用insert插入网络中的弧
    insert(u,v,c);
    insert(v,u,0);                  //插入一条反方向,当前容量为0的弧
}

void init(){
	memset(p,-1,sizeof(p));
    eid=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int x,y;
            x=(i-1)*m+j;
            y=x+m*n;
            addedge(x,y,1);
            for(int k=0;k<4;k++){
                int l=i+dx[k];
                int r=j+dy[k];
                if(l>=1&&l<=n&&r>=1&&r<=m){
                    x=(l-1)*m+r;
                    addedge(y,x,1);
                }else{

                    addedge(y,T,1);
                }
            }
        }
    }
}

int d[MAX_N];                        //存储每个顶点的层次

bool bfs(){
    memset(d,-1,sizeof(d));
    queue<int> q;
    q.push(S);
    d[S]=0;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=p[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(e[i].c>0&&d[v]==-1){
                q.push(v);
                d[v]=d[u]+1;
            }
        }
    }
    return (d[T]!=-1);
}

int dfs(int u,int flow){        //flow表示当前搜索分支的流量上限
    if(u==T){
        return flow;
    }
    int res=0;
    for(int i=p[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(e[i].c>0&&d[u]+1==d[v]){
            int tmp=dfs(v,min(flow,e[i].c));    // 递归计算顶点 v,用 c(u, v) 来更新当前流量上限
            flow-=tmp;
            e[i].c-=tmp;
            res+=tmp;
            e[i^1].c+=tmp;      // 修改反向弧的容量
            if(flow==0){        // 流量达到上限,不必继续搜索了
                break;
            }
        }
    }
    if(res==0){     // 当前没有经过顶点 u 的可行流,不再搜索顶点 u
          d[u]=-1;
    }
    return res;
}

int dinic(){        // 函数返回值就是最大流的结果
    int res=0;
    while(bfs()){
        res+=dfs(S,INF);    // 初始流量上限为 INF
    }
    return res;
}

int main() {
    int cas;
    scanf("%d",&cas);
    while(cas--){
        int bian;
        scanf("%d%d%d",&n,&m,&bian);
        S=0;
        T=n*m*2+1;
        init();
        for(int i=0;i<bian;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            addedge(S,(x-1)*m+y,1);
        }
        if(bian==dinic()){
            printf("possible\n");
        }else{
            printf("not possible\n");
        }
    }
    return 0;
}

ISAP:

#include <iostream>
#include <string.h>
#include <queue>
#include<bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAX_N=10000;     //顶点数上限
const int MAX_M=500000;    //总的边数上限

struct edge{
    int v,c,next;       //v指另一个顶点,c表示容量。
}e[MAX_M];

int p[MAX_N],eid;
int S,T;                             //S是源点,T是汇点。

int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};

void insert(int u,int v,int c){ //插入一条从u向v,容量为c的弧。
    e[eid].v=v;
    e[eid].next=p[u];
    e[eid].c=c;
    p[u]=eid++;
}

void addedge(int u,int v,int c){ //用insert插入网络中的弧
    insert(u,v,c);
    insert(v,u,0);                  //插入一条反方向,当前容量为0的弧
}

void init(int n,int m){
	memset(p,-1,sizeof(p));
    eid=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int x,y;
            x=(i-1)*m+j;
            y=x+m*n;
            addedge(x,y,1);
            for(int k=0;k<4;k++){
                int l=i+dx[k];
                int r=j+dy[k];
                if(l>=1&&l<=n&&r>=1&&r<=m){
                    x=(l-1)*m+r;
                    addedge(y,x,1);
                }else{

                    addedge(y,T,1);
                }
            }
        }
    }
}


int gap[MAX_N];
int dis[MAX_N];
int cur[MAX_N];
int pre[MAX_N];
int rec[MAX_N];

void BFS()
{
    int i;
    for(i = 0; i <= T; i++) dis[i] = INF;
    queue<int> q;
    q.push(T);
    dis[T] = 0;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        gap[dis[u]]++;
        for(i = p[u]; i != -1; i = e[i].next)
        {
            int v = e[i].v;
            if(dis[v] == INF && e[i^1].c)
            {
                dis[v] = dis[u] + 1;
                q.push(v);
            }
        }
    }
}


int SAP()
{
    int i;
    int u = pre[S] = S, Maxflow = 0, flow = INF;

    for(i = 0; i <= T; i++)//这里 T 为最大顶点编号
    {
        gap[i] = 0;
        cur[i] = p[i];
    }
    BFS();
    while(dis[S] <= T)
    {
        if(u == T)
        {
            Maxflow += flow;
            for(; u != S; u = pre[u])
            {
                e[rec[u]].c -= flow;
                e[rec[u]^1].c += flow;
            }
            flow = INF;
        }

        for(i = cur[u]; i != -1; i = e[i].next)
        {
            int v = e[i].v;
            if(e[i].c && dis[u] == dis[v] + 1)
            {
                flow = min(flow, e[i].c);
                pre[v] = u;
                rec[v] = i;
                cur[u] = i;//当前弧优化
                u = v;
                break;
            }
        }
        if(i == -1)
        {
            int mindis = T + 1;//T是顶点数
            if((--gap[dis[u]]) == 0) break;//间隙优化
            for(i = cur[u] = p[u]; i != -1; i = e[i].next)
            {
                if(e[i].c && mindis > dis[e[i].v])
                {
                    mindis = dis[e[i].v];
                }
            }
            gap[dis[u] = mindis+1]++;
            u = pre[u];
        }
    }
    return Maxflow;
}


int main() {
    int cas;
    scanf("%d",&cas);
    while(cas--){
        int bian;
        int n,m;
        scanf("%d%d%d",&n,&m,&bian);
        S=0;
        T=n*m*2+1;
        init(n,m);
        for(int i=0;i<bian;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            addedge(S,(x-1)*m+y,1);
        }
        if(bian==SAP()){
            printf("possible\n");
        }else{
            printf("not possible\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40679299/article/details/81146794