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("
");
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("
");
162         }
163     }
164     return 0;
165 }
View Code
原文地址:https://www.cnblogs.com/cnblogs321114287/p/4531639.html