HDU - 3338烦的一比网络流

本来想着要区域赛 就暂时不写题解了。
忍不住了,这题踩了太多坑了,状态也不太好,比起做的时间,写题解的时间怎么也不算多。

在这里插入图片描述

放两张图片 方便自己看
放两张图片 方便自己看

本质是一个方格填数的题
就这么几个格子
黑色

不能放值。
但他本身可有值
左值代表这个点向下直到下个黑点或者边界中的一列白格填的总数为这个左值
右值同理这个点向右直到下个黑点或者边界中的一行白格填的总数为这个左值

白色

被填的格子,其他用

这里建图真的是鬼斧神工,根本想不到。
首先按行相加的值和按列相加的值肯定是一致的。
这里的处理很巧妙从每行到每列建边
在这里插入图片描述
大概就是这么个意思,自己看的懂就行了。
源点连所有的黑点的左半部分(如果有值的话)
汇点连所有的黑点的右半部分(如果有值的话)

那么白点怎么处理?

连他左边第一个黑点(有值)和上面第一个黑点(有值),注意拆点,这里就不赘述了。

至于为什么? 你猜。

tm的200多行,输入有点恶心了。
ac代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
const int MAXN = 21000;//点数的最大值
const int MAXM = 1e7+10;//边数的最大值
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to,next,cap,flow;
} edge[MAXM]; //注意是MAXM
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],cur[MAXN];
void init()
{
    tol = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw = 0)
{
    edge[tol] = Edge{v,head[u],w,0};
    head[u] = tol++;
    edge[tol] =Edge{u,head[v],rw,0};
    head[v] = tol++;
}
int Q[MAXN];
void BFS(int start,int end)
{
    memset(dep,-1,sizeof(dep));
    memset(gap,0,sizeof(gap));
    gap[0] = 1;
    int front = 0, rear = 0;
    dep[end] = 0;
    Q[rear++] = end;
    while(front != rear)
    {
        int u = Q[front++];
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(dep[v] != -1)continue;
            Q[rear++] = v;
            dep[v] = dep[u] + 1;
            gap[dep[v]]++;
        }
    }
}
int S[MAXN];
int sap(int start,int end,int N)
{
    BFS(start,end);
    memcpy(cur,head,sizeof(head));
    int top = 0;
    int u = start;
    int ans = 0;
    while(dep[start] < N)
    {
        if(u == end)
        {
            int Min = INF;
            int inser;
            for(int i = 0; i < top; i++)
                if(Min > edge[S[i]].cap - edge[S[i]].flow)
                {
                    Min = edge[S[i]].cap - edge[S[i]].flow;
                    inser = i;
                }
            for(int i = 0; i < top; i++)
            {
                edge[S[i]].flow += Min;
                edge[S[i]^1].flow -= Min;
            }
            ans += Min;
            top = inser;
            u = edge[S[top]^1].to;
            continue;
        }
        bool flag = false;
        int v;
        for(int i = cur[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].to;
            if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u])
            {
                flag = true;
                cur[u] = i;
                break;
            }
        }
        if(flag)
        {
            S[top++] = cur[u];
            u = v;
            continue;
        }
        int Min = N;
        for(int i = head[u]; i != -1; i = edge[i].next)
            if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
            {
                Min = dep[edge[i].to];
                cur[u] = i;
            }
        gap[dep[u]]--;
        if(!gap[dep[u]])return ans;
        dep[u] = Min + 1;
        gap[dep[u]]++;
        if(u != start)u = edge[S[--top]^1].to;
    }
    return ans;
}
int G[110][110][2];//0--下 1--右


char tmp[10];

int shift(int x){
    int s,e;
    if(x==1) s=0,e=2;
    else s=4,e=6;
    int ans=0;
    for(int i=s;i<=e;i++){
        ans=ans*10+tmp[i]-'0';
    }
    return ans;
}

int n,m;
int right(int x,int y){
    int i=1;
    while(y+i<=m && G[x][y+i][0]==-2){
        i++;
    }
    return i-1;
}
int down(int x,int y){
    int i=1;
    while(x+i<=n&&G[x+i][y][0]==-2){
        i++;
    }
    return i-1;
}
//int G[MAXN][MAXN][2];//0--下 1--右

int upb(int x,int y){ //1
    int i=-1;
    while(x+i>0&&G[x+i][y][0]==-2){
        i--;
    }
    return x+i;
}
int leftb(int x,int y){ //0
    int i=-1;
    while(y+i>0&&G[x][y+i][0]==-2){
        i--;
    }
    return y+i;
}
void show(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++)
        cout<<G[i][j][0]<<" "<<G[i][j][1]<<"  ";
        cout<<endl;
    }
}
//int G[MAXN][MAXN][2];//0--下 1--右

int eee(int x,int y){
    int pos=(x-1)*m+y;
    for(int u=head[pos];~u;u=edge[u].next){
        return edge[u].flow;
    }
}

int main()
{
    while(~scanf("%d%d",&n,&m)){
        init();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%s",tmp);
                if(tmp[0]=='.') G[i][j][0]=G[i][j][1]=-2;
                else {
                    if(tmp[0]=='X') G[i][j][0]=-1;
                    else {
                        G[i][j][0]=shift(1);
                    }
                    if(tmp[4]=='X') G[i][j][1]=-1;
                    else G[i][j][1]=shift(0);
                }
            }
        }
//先处理权值
//源点
//汇点
        int s=0,e=2*n*m+1;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(G[i][j][0]>0){//是个黑点
                G[i][j][0]-=down(i,j);
                //cout<<G[i][j][0]<<" "<<i<<" "<<j<<endl;
                addedge(n*m+(i-1)*m+j,e,G[i][j][0]);
            }
            if(G[i][j][1]>0){//是个黑点
                G[i][j][1]-=right(i,j);
                //cout<<G[i][j][1]<<" "<<i<<" "<<j<<endl;
                addedge(s,(i-1)*m+j,G[i][j][1]);
            }
        }
//对白点加边
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(G[i][j][0]==-2){
                int yy=leftb(i,j);
                int xx=upb(i,j);
                addedge((i-1)*m+yy,(i-1)*m+j,8);
                addedge((i-1)*m+j,n*m+(xx-1)*m+j,8);
            }
        }
        int flow=sap(s,e,e+1);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(G[i][j][0]!=-2) printf("_%c"," \n"[j==m]);
                if(G[i][j][0]==-2){
                       printf("%d%c",1+eee(i,j)," \n"[j==m]);
                }
            }
        }

    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/wyxxzsy/article/details/83005760