hdu3338 神奇网络流(最大流) Kakuro Extension

大意:

 

原数谜是个很有趣的游戏,如图,每一行或每一列空白称为一个回,每一回都对应着一个整数sum,sum就是这回的和。这些空白格里只能填入1—9这九个数字,且在每一回中不能重复。全黑色的格为空,有数字的格,左下角的表示列的和,右上角的表示行的和,则可以得到下面这个图。

但这道题不是原来的数谜,这题与原数谜相比,少了一点规则,就是,每一回中出现的数字可以重复。给你一个n * m 的图,让你填充一下。

看了这题,没有多少思路,借鉴一下解题报告的思想,这题可以用网络流做。以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变。求满足的最大流。由于流量有上下限限制,可以给每个数都减掉1,则填出来的数字范围为0—8, 就可以用单纯的网络流搞定了。求出来再加上就可以了。

建图:

一共有四类点:

1. 构造源点S,汇点T

2. 有行和的格子,此类节点设为A

3. 空白格,设为B

4. 有列和的格子,设为C

则可以建边:

1. <S, A> 容量和行和

2. <A, B> 容量为8

3. <B, C> 容量为8

4. <C, T> 容量为列和

当然,反向边容量都置为0。

题目的sample input貌似有错误 我的输出和sample output不一样我调试了好久 不知道哪错了 但是我在网上看了其他人的代码 算出的答案和我一样 我就把我的试着A下结果居然过了 哈哈

#include<iostream> 
#include<stdio.h> 
#include<memory.h> 
#include<cmath> 
using namespace std;   
#define MAXN 50005 
#define MAXE 1000002 
#define INF 0xffffff      
int ne,nv,tmp,s,t,index;  
struct Edge{ 
    int next,pair; 
    int v,cap,fLow; 
}edge[MAXE];
struct gg
{
    int x,y;
    int val;
}row[MAXN],col[MAXN];
int emp,row_num,col_num;
int map[102][102];
int net[MAXN]; 
int ISAP() 
{ 
	int numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN]; 
 
    int cur_fLow,max_fLow,u,tmp,neck,i; 
    memset(dist,0,sizeof(dist)); 
    memset(numb,0,sizeof(numb)); 
    memset(pre,-1,sizeof(pre)); 
    for(i = 1 ; i <= nv ; ++i) 
        curedge[i] = net[i]; 
    numb[nv] = nv; 
    max_fLow = 0; 
    u = s; 
    while(dist[s] < nv) 
    { 
        if(u == t) 
        { 
            cur_fLow = INF; 
            for(i = s; i != t;i = edge[curedge[i]].v)  
            {   
                if(cur_fLow > edge[curedge[i]].cap) 
                { 
                    neck = i; 
                    cur_fLow = edge[curedge[i]].cap; 
                } 
            } 
            for(i = s; i != t; i = edge[curedge[i]].v) 
            { 
                tmp = curedge[i]; 
                edge[tmp].cap -= cur_fLow; 
                edge[tmp].fLow += cur_fLow; 
                tmp = edge[tmp].pair; 
                edge[tmp].cap += cur_fLow; 
                edge[tmp].fLow -= cur_fLow; 
            } 
            max_fLow += cur_fLow; 
            u = neck; 
        } 
        /* if .... eLse ... */
        for(i = curedge[u]; i != -1; i = edge[i].next) 
            if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1) 
                break; 
        if(i != -1) 
        { 
            curedge[u] = i; 
            pre[edge[i].v] = u; 
            u = edge[i].v; 
        }else{ 
            if(0 == --numb[dist[u]]) break; 
            curedge[u] = net[u]; 
            for(tmp = nv,i = net[u]; i != -1; i = edge[i].next) 
                if(edge[i].cap > 0) 
                    tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v]; 
            dist[u] = tmp + 1; 
            ++numb[dist[u]]; 
            if(u != s) u = pre[u]; 
        } 
    }      
    return max_fLow; 
}
void addedge(int u,int v,int f)
{
	edge[index].next = net[u]; 
    edge[index].v = v; 
    edge[index].cap = f; 
    edge[index].fLow = 0; 
    edge[index].pair = index+1; 
    net[u] = index++; 
    edge[index].next = net[v]; 
    edge[index].v = u; 
    edge[index].cap = 0; 
    edge[index].fLow = 0; 
    edge[index].pair = index-1; 
    net[v] = index++;
	
}
int print( int tp ) 
{
	int ans = 0;
	int id = tp + row_num+1;
	for( int i = net[id] ; i != -1 ; i = edge[i].next ) 
	{
		int v = edge[i].v;
		if( v <=row_num+1 )
		{ 
			ans+= edge[i].cap;
			break;
		}
	}
	return ans+1;
}  
int main() { 
    int i,j,m,n;     
	char ts[15]; 
    while(scanf("%d%d",&n,&m)!=EOF) 
    {
		emp=row_num=col_num=0;
		for(i=0;i<n;i++)
        for(j=0;j<m;j++)
        {
			scanf("%s",ts);
			if(ts[0]=='.')
            {
				map[i][j]=++emp;    
            }
            else
            {
				map[i][j]=-1;
				if(ts[4]!='X')
                {
					int tp=(ts[4]-'0')*100+(ts[5]-'0')*10+ts[6]-'0';
                    row[++row_num].x=i;
                    row[row_num].y=j;
                    row[row_num].val=tp;                   
				}
                if(ts[0]!= 'X' ) 
				{
                	int tp = (ts[0]-'0')*100+(ts[1]-'0')*10+ts[2]-'0';
                    col[++col_num].x = i;
                    col[col_num].y = j;
                    col[col_num].val = tp;
                }     
			}                 
		}
		t=emp+col_num+row_num+2; 
		nv=t;// 有m+2个点 
		index=0;//index从0开始扫 
        s = 1; 
        memset(net,-1,sizeof(net));
        for(i=1;i<=row_num;i++)
        {
			int pos = i;
            int x = row[i].x;
            int y = row[i].y;
            int cnt_len = 0;
            for( y=y+1; y <m ; y++ ) 
			{
				if( map[x][y] != -1 ) 
				{
					cnt_len++;
             		addedge(i+1, row_num+ map[x][y]+1,8);
                } 
				else break;
            }
            addedge(s,pos+1,row[i].val-cnt_len);
		}
        for( i = 1 ; i <=col_num ; i++ ) 
		{
			int pos =i+1+row_num+emp;
			int x = col[i].x;
			int y = col[i].y;
			int cnt_len = 0;
			for( x=x+1 ; x < n ; x++ ) 
			{
				if( map[x][y] != -1 ) //为白点 
				{
					cnt_len++;
             		addedge(row_num+ map[x][y]+1,pos,8);
				} 
				else break;
            }
            addedge(pos,t,col[i].val-cnt_len);
		}
		ISAP();
		for(i=0;i<n;i++)
        {
			for(j=0;j<m;j++)
         	{
				if(map[i][j]==-1)
				printf("_ ");
				else
				//输出的时候加上当前边的流就可以了 
				printf("%d ",print(map[i][j]));    
         	}
			printf("\n");
		} 
    } 
    return 0; 
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值