题意:
黑格子右上代表该行的和,左下代表该列下的和
链接:点我
这题可以用网络流做。以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变。求满足的最大流。由于流量有上下限限制,可以给每个数都减掉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 }
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 }