hdu 3338 最大流 ****

题意:

黑格子右上代表该行的和,左下代表该列下的和

链接:点我

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

这一题主要是在建图

建图:

一共有四类点:

1. 构造源点ST,汇点ED

2. 有行和的格子,即\上面有值的格子,此类节点设为A

3. 空白格,设为B

4. 有列和的格子,即\下面有值的格子,设为C

则可以建边:

1. ST------------A         容量:行和

2. A----------- B          容量:8

3. B------------C          容量:8

4. C------------ED          容量:列和

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

就是这么难~~

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 using namespace std;
  5
  6
  7 #define INF 999999999
  8 #define MAXN 14000
  9 #define RE(x) (x)^1
 10
 11 int head[MAXN];
 12 int map[120][120];
 13 int st,ed;
 14 struct Edge
 15 {
 16     int v,next;
 17     int val;
 18     Edge(){}
 19     Edge( int V , int NEXT , int W = 0 ):v(V),next(NEXT),val(W){}
 20 }edge[500000];
 21
 22 struct gg
 23 {
 24     int x,y;
 25     int val;
 26 }row[MAXN],col[MAXN];
 27 int emp,row_num,col_num;
 28 int lvl[MAXN], gap[MAXN];
 29 int cnt_edge;
 30 int n,m,T;
 31 int empty[MAXN];
 32
 33 void Insert_Edge( int u , int v , int flow = 0 ) {
 34
 35     edge[cnt_edge] = Edge(v,head[u],flow);
 36     head[u] = cnt_edge++;
 37     edge[cnt_edge] = Edge(u,head[v]);
 38     head[v] = cnt_edge++;
 39
 40 }
 41
 42 void Init(){
 43     cnt_edge = 0;
 44     memset(head,-1,sizeof(head));
 45      memset(lvl, 0, sizeof (lvl));
 46     memset(gap, 0, sizeof (gap));
 47 }
 48
 49 int dfs(int u, int flow)
 50 {
 51     if (u==ed) {
 52         return flow;
 53     }
 54     int tf = 0, sf, mlvl = ed-1;
 55     for (int i= head[u]; i != -1; i = edge[i].next) {
 56         if (edge[i].val > 0) {
 57             if (lvl[u] ==lvl[edge[i].v]+1) {
 58                 sf = dfs(edge[i].v, min(flow-tf, edge[i].val));
 59                 edge[i].val -= sf;
 60                 edge[RE(i)].val += sf;
 61                 tf += sf;
 62                 if (lvl[st] >=ed) {
 63                     return tf;
 64                 }
 65                 if (tf == flow) {
 66                     break;
 67                 }
 68             }
 69             mlvl = min(mlvl, lvl[edge[i].v]);
 70         }
 71     }
 72     if (tf == 0) {
 73         --gap[lvl[u]];
 74         if (!gap[lvl[u]]) {
 75             lvl[st] =ed;
 76         }
 77         else {
 78             lvl[u] = mlvl+1;
 79             ++gap[lvl[u]];
 80         }
 81     }
 82     return tf;
 83 }
 84
 85 int sap()
 86 {
 87     int ans = 0;
 88     gap[0]=ed;
 89     while (lvl[st] <ed) {
 90         ans += dfs(st, INF);
 91     }
 92     return ans;
 93 }
 94
 95 int print( int tp ) {
 96     int ans = 0;
 97     int id = tp + row_num+1;
 98     for( int i = head[id] ; i != -1 ; i = edge[i].next ) {
 99         int v = edge[i].v;
100         if( v <=row_num+1 )
101         {
102           ans+= edge[i].val;
103           break;
104         }
105     }
106     return ans+1;
107 }
108
109 int main()
110
111 {
112
113     int i,j;
114
115     char s[15];
116
117     while(scanf("%d%d",&n,&m)!=-1)
118     {
119         emp=row_num=col_num=0;
120         for(i=0;i<n;i++)
121         for(j=0;j<m;j++)
122         {
123             scanf("%s",s);
124             if(s[0]==‘.‘)
125             {
126                 map[i][j]=++emp;
127             }
128             else
129             {
130                 map[i][j]=-1;
131                 if(s[4]!=‘X‘)
132                 {
133                         int tp=(s[4]-‘0‘)*100+(s[5]-‘0‘)*10+s[6]-‘0‘;
134                         row[++row_num].x=i;
135                         row[row_num].y=j;
136                         row[row_num].val=tp;
137
138
139                 }
140                 if(s[0]!= ‘X‘ ) {
141                         int tp = (s[0]-‘0‘)*100+(s[1]-‘0‘)*10+s[2]-‘0‘;
142                         col[++col_num].x = i;
143                         col[col_num].y = j;
144                         col[col_num].val = tp;
145                     }
146
147             }
148
149         }
150         T=emp+col_num+row_num+2;
151         st=1;
152         ed=T;
153         Init();
154         for(i=1;i<=row_num;i++)
155         {
156             int pos = i;
157             int x = row[i].x;
158             int y = row[i].y;
159             int cnt_len = 0;
160             for( y=y+1; y <m ; y++ ) {
161                 if( map[x][y] != -1 ) {
162                     cnt_len++;
163             Insert_Edge(i+1, row_num+ map[x][y]+1,8);
164                 } else break;
165             }
166             Insert_Edge(st,pos+1,row[i].val-cnt_len);
167         }
168
169         for( i = 1 ; i <=col_num ; i++ ) {
170             int pos =i+1+row_num+emp;
171             int x = col[i].x;
172             int y = col[i].y;
173             int cnt_len = 0;
174             for( x=x+1 ; x < n ; x++ ) {
175                 if( map[x][y] != -1 ) {
176                     cnt_len++;
177             Insert_Edge(row_num+ map[x][y]+1,pos,8);
178
179                 } else break;
180             }
181             Insert_Edge(pos,ed,col[i].val-cnt_len);
182         }
183         sap();
184         for(i=0;i<n;i++)
185         {
186         for(j=0;j<m;j++)
187         {
188
189             if(map[i][j]==-1)
190             printf("_ ");
191             else
192             printf("%d ",print(map[i][j]));
193         }
194         printf("\n");
195     }
196     }
197
198     return 0;
199 }

2015/5/26

kuangbin大法:

  1 /*
  2  * HDU 3338 Kakuro Extension
  3  * 题目意思就是在n*m的格子中,有黑白两种格子。要在白格子中填入数字1~9
  4  * 每一段横竖连续的白格子的和是知道的。
  5  * 求出一种满足的,保证有解。
  6  * 最大流。
  7  * 按照横竖段进行编号。然后行进列出,构造图形。
  8  *
  9  * 为了保证填入的数字是1~9,所以一开始每个格子减掉了1,相应的流入和流出都减掉。
 10  * 然后格子的边的赋值为8.
 11  * 还有就是要记录下相应边的编号,便于输出结果。
 12  *
 13  */
 14
 15 #include <iostream>
 16 #include <string.h>
 17 #include <algorithm>
 18 #include <stdio.h>
 19 using namespace std;
 20
 21 const int MAXN=20010;
 22 const int MAXM=200010;
 23 const int INF=0x3f3f3f3f;
 24 struct Node
 25 {
 26     int to,next,cap;
 27 }edge[MAXM];
 28 int tol;
 29 int head[MAXN];
 30 int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];
 31 void init()
 32 {
 33     tol=0;
 34     memset(head,-1,sizeof(head));
 35 }
 36 void addedge(int u,int v,int w,int rw=0)
 37 {
 38     edge[tol].to=v;edge[tol].cap=w;edge[tol].next=head[u];head[u]=tol++;
 39     edge[tol].to=u;edge[tol].cap=rw;edge[tol].next=head[v];head[v]=tol++;
 40 }
 41 int sap(int start,int end,int nodenum)
 42 {
 43     memset(dis,0,sizeof(dis));
 44     memset(gap,0,sizeof(gap));
 45     memcpy(cur,head,sizeof(head));
 46     int u=pre[start]=start,maxflow=0,aug=-1;
 47     gap[0]=nodenum;
 48     while(dis[start]<nodenum)
 49     {
 50         loop:
 51         for(int  &i=cur[u];i!=-1;i=edge[i].next)
 52         {
 53             int v=edge[i].to;
 54             if(edge[i].cap&&dis[u]==dis[v]+1)
 55             {
 56                 if(aug==-1||aug>edge[i].cap)
 57                     aug=edge[i].cap;
 58                 pre[v]=u;
 59                 u=v;
 60                 if(v==end)
 61                 {
 62                     maxflow+=aug;
 63                     for(u=pre[u];v!=start;v=u,u=pre[u])
 64                     {
 65                         edge[cur[u]].cap-=aug;
 66                         edge[cur[u]^1].cap+=aug;
 67                     }
 68                     aug=-1;
 69                 }
 70                 goto loop;
 71             }
 72         }
 73         int mindis=nodenum;
 74         for(int i=head[u];i!=-1;i=edge[i].next)
 75         {
 76             int v=edge[i].to;
 77             if(edge[i].cap&&mindis>dis[v])
 78             {
 79                 cur[u]=i;
 80                 mindis=dis[v];
 81             }
 82         }
 83         if((--gap[dis[u]])==0)break;
 84         gap[dis[u]=mindis+1]++;
 85         u=pre[u];
 86     }
 87     return maxflow;
 88 }
 89
 90 char str[110][110][10];
 91 int lx[110][110];//存横条的标号
 92 int ly[110][110];//存竖条的标号
 93 int num[20010];//记录lx,ly数组中出现的次数,因为题目要求填入的数字是1~9,所以先全部变1,相应的流要减少
 94 int id[110][110];//相应的边的编号,便于最后统计结果
 95
 96 int main()
 97 {
 98     //freopen("in.txt","r",stdin);
 99     //freopen("out.txt","w",stdout);
100     int n,m;
101     while(scanf("%d%d",&n,&m)==2)
102     {
103         for(int i=0;i<n;i++)
104             for(int j=0;j<m;j++)
105                 scanf("%s",str[i][j]);
106         init();
107         int tt=0;//结点标号
108         memset(lx,0,sizeof(lx));
109         memset(ly,0,sizeof(ly));
110         memset(num,0,sizeof(num));
111         for(int i=0;i<n;i++)
112             for(int j=0;j<m;j++)
113             {
114                 if(strcmp(str[i][j],".......")!=0)continue;
115                 if(j==0 || lx[i][j-1]==0)lx[i][j]=++tt;
116                 else lx[i][j]=lx[i][j-1];
117                 num[lx[i][j]]++;
118             }
119         for(int j=0;j<m;j++)
120             for(int i=0;i<n;i++)
121             {
122                 if(strcmp(str[i][j],".......")!=0)continue;
123                 if(i==0 || ly[i-1][j]==0)ly[i][j]=++tt;
124                 else ly[i][j]=ly[i-1][j];
125                 num[ly[i][j]]++;
126             }
127         int start=0,end=tt+1,nodenum=tt+2;
128         for(int i=0;i<n;i++)
129             for(int j=0;j<m;j++)
130                 if(strcmp(str[i][j],".......")==0)
131                 {
132                     addedge(lx[i][j],ly[i][j],8);
133                     id[i][j]=tol-2;//记录下来
134                 }
135         for(int i=0;i<n;i++)
136             for(int j=0;j<m;j++)
137             {
138                 if(str[i][j][3]!=‘\\‘)continue;
139                 if(str[i][j][0]!=‘X‘)
140                 {
141                     int tmp=(str[i][j][0]-‘0‘)*100+(str[i][j][1]-‘0‘)*10+(str[i][j][2]-‘0‘);
142                     if(ly[i+1][j]!=0)
143                         addedge(ly[i+1][j],end,tmp-num[ly[i+1][j]]);
144                 }
145                 if(str[i][j][4]!=‘X‘)
146                 {
147                     int tmp=(str[i][j][4]-‘0‘)*100+(str[i][j][5]-‘0‘)*10+(str[i][j][6]-‘0‘);
148                     if(lx[i][j+1]!=0)
149                         addedge(start,lx[i][j+1],tmp-num[lx[i][j+1]]);
150                 }
151             }
152         sap(start,end,nodenum);
153         for(int i=0;i<n;i++)
154         {
155             for(int j=0;j<m;j++)
156             {
157                 if(j>0)printf(" ");
158                 if(strcmp(str[i][j],".......")!=0)printf("_");
159                 else printf("%c",‘0‘+9-edge[id[i][j]].cap);
160             }
161             printf("\n");
162         }
163     }
164     return 0;
165 }

时间: 2024-10-19 14:27:01

hdu 3338 最大流 ****的相关文章

Kakuro Extension (hdu 3338 最大流 建图难)

Kakuro Extension Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1093    Accepted Submission(s): 377 Special Judge Problem Description If you solved problem like this, forget it.Because you nee

hdu 3338 Kakuro Extension(最大流)

hdu 3338 Kakuro Extension Description If you solved problem like this, forget it.Because you need to use a completely different algorithm to solve the following one. Kakuro puzzle is played on a grid of "black" and "white" cells. Apart

Leapin&#39; Lizards (hdu 2732 最大流)

Leapin' Lizards Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1433    Accepted Submission(s): 586 Problem Description Your platoon of wandering lizards has entered a strange room in the labyr

hdu 4888 最大流给出行列和求矩阵

第一步,考虑如何求是否有解.使用网络流求解,每一行和每一列分别对应一个点,加上源点和汇点一共有N+M+2个点.有三类边: 1. 源点 -> 每一行对应的点,流量限制为该行的和 2. 每一行对应的点 -> 每一列对应的点,流量限制为 K 3. 每一列对应的点 -> 汇点,流量限制为该列的和 对上图做最大流,若源点出发的边和到达汇点的边全都满流,则有解,否则无解.若要求构造方案,则 (i,j) 对应的整数就是行 i–> 列 j 的流量. 第二步,考虑解是否唯一.显然,解唯一的充分必要条

hdu 4975最大流与4888类似但是有很吊的优化最大流

//来自潘神的优化 #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define inf 0x3fffffff #define N 1100 struct node { int u,v,w,next; }bian[N*N*4]; int head[N],yong,dis[N],work[N]; void init(){ yong=0; memset(head,-1,si

HDU 3338 Kakuro Extension(网络流)

HDU 3338 Kakuro Extension 题目链接 题意:完成如图的游戏,填充数字1-9 思路:网络流的行列模型,把每行每列连续的一段拆分出来建图即可,然后题目有限制一个下限1,所以 每行每列的容量减去相应的数字,然后建图建容量8就好,这样就默认原来容量已经有1了 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespac

hdu 2686 费用流 / 双线程DP

题意:给一个方阵,求从左上角出到右下角(并返回到起点),经过每个点一次不重复,求最大获益(走到某处获得改点数值),下来时每次只能向右或向下,反之向上或向左. 俩种解法: 1  费用流法:思路转化:从左上角流出2的流量,(表示走俩条路),归于右下角,可以走就有边(右和下),权为负的费用,源点连起点,汇点连终点,流量为2. 除源汇外所有点一分为2,Y向X对应点有流量1的边,之前边为X到Y的(原图),这样处理解决每个点只最多走一次(除了源汇外)(X部只出,Y部要出必先回到X对应点).跑最小费用最大流即

HDU - 3338 Kakuro Extension(最大流)

题目大意:看一下图基本就知道了 解题思路:难点是构图.. 设置一个超级源点和所有的行的和相连,容量为该行的和 - 该行和由几个数相加得到 设置一个超级汇点,和所有列的和相连,容量为该列的和 - 该列和由几个数相加得到 接着就是空白部分和 "行和"和 "列和"的关系了 空白连向该行的行和,权值为8 空白连向该列的列和,权值也为8 为什么为8,而不是9,因为流量也可能为0,但是0是不能填的,所以将容量设为8,最后取值的时候加1即可 #include <cstdio

L - Kakuro Extension - HDU 3338 - (最大流)

题意:有一个填数字的游戏,需要你为白色的块内填一些值,不过不能随意填的,是有一些规则的(废话),在空白的上方和作方给出一些值,如果左下角有值说明下面列的和等于这个值,右上角的值等于这行后面的数的和,如下图示,现在把空白的地方填上数字即可(只能填从1~9的数字,不限制一行是否有重复数字). 分析:如果这道题不在网络流专题里面估计很难向网络流这样面去想(看不出来),不过如果刻意往这个地方想的话还是能想到的,首先可以观察出来行的和等于列的和,所以用行和列的一边当源一边当汇,然后用每个白块与相对应的行列