【网络流】hdu3338 Kakuro Extension

题意:原数谜是个很有趣的游戏,每一行或每一列空白称为一个回,每一回都对应着一个整数sum,sum就是这回的和。这些空白格里只能填入1—9这九个数字,且在每一回中不能重复。全黑色的格为空,有数字的格,左下角的表示列的和,右上角的表示行的和。但这道题不是原来的数谜,这题与原数谜相比,少了一点规则,就是,每一回中出现的数字可以重复。给你一个n * m 的图,让你填充一下。
难度:4
题解:这题挺有意思的告诉我们每行每列之和,要我们求每个点的流量。我的建图方法太麻烦了,不过也先介绍一下。就是把空白的每个点,都当成最大流中的一个点。(构成点集E)所有行和构成点集R,所有列和构成点集C。然后建图:S->R->E->C->T.流量分别是,行和-改行和包含的元素数,8,8,列和-该列和包含的元素数为什么容量是8?为什么要减去元素数?因为我们只能用1-9填空,那么每个格子最少有1。为了把有上下限的网络流(容量最少为1,最多为9)转化为一般的网络流,减去元素数之后,我们要用0-8填空就行了。最后求点集E流向R的流量就是(该点要求的数-1)其实有一种更简单的方法,意思差不多。只是不要点集E,直接行和列相连接。Amb大牛用的就是这种方法,代码比我少了2k。。
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 20500
#define maxm 205000
#define inf 2000000000
using namespace std;
int gap[maxn],dis[maxn],pre[maxn],cur[maxn];
int n,NV,m;
struct Edge {
    int v,val;
    int next;
    Edge(){}
    Edge( int V , int NEXT , int W = 0 ):v(V),next(NEXT),val(W){}
}edge[maxm];
int cnt_edge,head[maxn];
void Insert_Edge( int u , int v , int flow = 0 ) {
    edge[cnt_edge] = Edge(v,head[u],flow);
    head[u] = cnt_edge++;
    edge[cnt_edge] = Edge(u,head[v]);
    head[v] = cnt_edge++;
}
void Init() {
    cnt_edge = 0;
    memset(head,-1,sizeof(int)*(NV+1));
}
int Sap( int st, int en )
{
    memset(dis,0,sizeof(int)*( NV+1));
    memset(gap,0,sizeof(int)*( NV+1));
    for( int i  = 0 ; i <  NV ; i++ )
        cur[i] = head[i];
    int u = pre[st] = st,maxflow = 0,aug = inf;
    gap[0] = NV;
    while( dis[st] < NV )
    {
loop:    for( int &i = cur[u]; i != -1 ; i = edge[i].next ) {
            int v =edge[i].v;
            if( edge[i].val && dis[u] == dis[v]+1) {
                aug = aug <  edge[i].val? aug: edge[i].val;
                pre[v] = u;
                u = v;
                if( v == en ) {
                    maxflow += aug;
                    for( u = pre[u]; v != st ; v = u,u = pre[u] ) {
                         edge[cur[u]].val -= aug;
                         edge[cur[u]^1].val += aug;
                    }
                    aug = inf;
                }
                goto loop;
            }
        }
        int mindis =  NV;
        for( int i =  head[u]; i != -1 ; i =  edge[i].next ) {
            int v =  edge[i].v;
            if(  edge[i].val && 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;
}
struct Node {
    int x,y,val;
}row[10005],col[10005];
int matrix[105][105];
int cnt_row,cnt_col,cnt_empty;
char cc[15];
void print( int tp ) {
    int ans = 0;
    int id = tp + cnt_col + cnt_row;
    for( int i = head[id] ; i != -1 ; i = edge[i].next ) {
        int v = edge[i].v;
        if( v < cnt_row ) ans += edge[i].val;
    }
    printf("%d",ans+1);
}
int main() {
    while( scanf("%d%d",&n,&m) != EOF ) {
        cnt_row = cnt_col = cnt_empty = 0;
        for( int i = 0 ; i < n ; i++ )
            for( int j = 0 ; j < m ; j++ ) {
                scanf("%s",cc);
                if( cc[0] == '.' ) {
                    matrix[i][j] = cnt_empty++;
                } else {
                    matrix[i][j] = -1;
                    if( cc[4] != 'X' ) {
                        int tp = (cc[4]-'0')*100+(cc[5]-'0')*10+cc[6]-'0';
                        row[cnt_row].x = i;
                        row[cnt_row].y = j;
                        row[cnt_row++].val = tp;
                    }
                    if( cc[0] != 'X' ) {
                        int tp = (cc[0]-'0')*100+(cc[1]-'0')*10+cc[2]-'0';
                        col[cnt_col].x = i;
                        col[cnt_col].y = j;
                        col[cnt_col++].val = tp;
                    }
                }
            }
        NV = cnt_col + cnt_row + 2 + cnt_empty;
        Init();
        int st = NV - 2;
        int en = NV - 1;
        for( int i = 0 ; i < cnt_row ; i++ ) {
            int pos = i;
            int x = row[i].x;
            int y = row[i].y;
            int cnt_len = 0;
            for( y++ ; y < m ; y++ ) {
                if( matrix[x][y] != -1 ) {
                    cnt_len++;
                    Insert_Edge(i, cnt_row + cnt_col + matrix[x][y],8);
                } else break;
            }
            Insert_Edge(st,pos,row[i].val-cnt_len);
        }
        for( int i = 0 ; i < cnt_col ; i++ ) {
            int pos = cnt_row+i;
            int x = col[i].x;
            int y = col[i].y;
            int cnt_len = 0;
            for( x++ ; x < n ; x++ ) {
                if( matrix[x][y] != -1 ) {
                    cnt_len++;
                    Insert_Edge(cnt_row+cnt_col+matrix[x][y],pos,8);
                } else break;
            }
            Insert_Edge(pos,en,col[i].val-cnt_len);
        }
        Sap(st,en);
        for( int i = 0 ; i < n ; i++ ) {
            for( int j = 0 ; j < m ; j++ ) {
                if( matrix[i][j] == -1 ) printf("_");
                else print( matrix[i][j] );
                if( j != m -1 ) printf(" ");
            }
            puts("");
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值