标签:kakuro extension hdu 3338 最大流 建图难
6 6 XXXXXXX XXXXXXX 028\XXX 017\XXX 028\XXX XXXXXXX XXXXXXX 022\022 ....... ....... ....... 010\XXX XXX\034 ....... ....... ....... ....... ....... XXX\014 ....... ....... 016\013 ....... ....... XXX\022 ....... ....... ....... ....... XXXXXXX XXXXXXX XXX\016 ....... ....... XXXXXXX XXXXXXX 5 8 XXXXXXX 001\XXX 020\XXX 027\XXX 021\XXX 028\XXX 014\XXX 024\XXX XXX\035 ....... ....... ....... ....... ....... ....... ....... XXXXXXX 007\034 ....... ....... ....... ....... ....... ....... XXX\043 ....... ....... ....... ....... ....... ....... ....... XXX\030 ....... ....... ....... ....... ....... ....... XXXXXXX
_ _ _ _ _ _ _ _ 5 8 9 _ _ 7 6 9 8 4 _ 6 8 _ 7 6 _ 9 2 7 4 _ _ _ 7 9 _ _ _ _ _ _ _ _ _ _ _ 1 9 9 1 1 8 6 _ _ 1 7 7 9 1 9 _ 1 3 9 9 9 3 9 _ 6 7 2 4 9 2 _
题意:n*m的黑白格子,填数字,使白色区域的行列值的和等于有值得黑色区域的相对应的值。
思路:网络流,添加超级源点和汇点,源点和每行中有和值的点相连,汇点和每列中有和值的点相连,每行中有和值的点和该行中对应空白格相连,权值为8,同样每列中有和值的点和该列中对应的空白格相连,权值为8。因为数组开大了,memset时超时了,T了两天,简直了。
后来看到网上的建图方法,是把一整行当作一个点,这样建图简单一点,比我的代码要快。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #pragma comment (linker,"/STACK:102400000,102400000") #define maxn 11000 #define MAXN 200005 #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define FRE(i,a,b) for(i = a; i <= b; i++) #define FREE(i,a,b) for(i = a; i >= b; i--) #define FRL(i,a,b) for(i = a; i < b; i++) #define FRLL(i,a,b) for(i = a; i > b; i--) #define mem(t, v) memset ((t) , v, sizeof(t)) #define sf(n) scanf("%d", &n) #define sff(a,b) scanf("%d %d", &a, &b) #define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c) #define pf printf #define DBG pf("Hi\n") typedef long long ll; using namespace std; struct Edge { int u,v,cap,next; }edge[MAXN]; int head[maxn],cur[maxn],level[maxn]; int num,n,m,cnt; int row_sum[101][101],col_sum[101][101];//(i,j)位置的行,列之和 int row_cnt[101],col_cnt[101]; int number_col[101][101]; //行标号 int number_row[101][101]; //列标号 int number_w[101][101]; //空白处标号 int id[101][101]; //相应的边编号,用于最后输出 char str[101][101][8]; void init() { num=0;cnt=1; mem(head,-1); mem(col_sum,0); mem(row_sum,0); mem(col_cnt,0); mem(row_cnt,0); mem(number_col,0); mem(number_row,0); mem(number_w,0); mem(id,0); } void addedge(int u,int v,int w) { edge[num].u=u; edge[num].v=v; edge[num].cap=w; edge[num].next=head[u]; head[u]=num++; edge[num].u=v; edge[num].v=u; edge[num].cap=0; edge[num].next=head[v]; head[v]=num++; } bool bfs(int s,int t) { mem(level,-1); queue<int>Q; Q.push(s); level[s]=0; while (!Q.empty()) { int u=Q.front(); Q.pop(); for (int i=head[u];i+1;i=edge[i].next) { int v=edge[i].v; if (level[v]==-1&&edge[i].cap>0) { level[v]=level[u]+1; Q.push(v); } } } return level[t]!=-1; } int dfs(int u,int t,int f) { if (u==t) return f; for (int &i=cur[u];i+1;i=edge[i].next) { int v=edge[i].v; if (level[v]==level[u]+1&&edge[i].cap>0) { int d=dfs(v,t,min(f,edge[i].cap)); if (d>0) { edge[i].cap-=d; edge[i^1].cap+=d; return d; } } } return 0; } int dinic(int s,int t,int node) { int flow=0; while (bfs(s,t)) { for (int i=0;i<=node;i++) cur[i]=head[i]; int f; while ((f=dfs(s,t,INF))>0) flow+=f; } return flow; } void build() //建图 { int i,j; for (i=0;i<n;i++) { for (j=0;j<m;j++) { scanf("%s",str[i][j]); if (isdigit(str[i][j][0])) { int t=(str[i][j][0]-'0')*100+(str[i][j][1]-'0')*10+str[i][j][2]-'0'; col_sum[i][j]=t; //保存下(i,j)位置表示的该行数字之和 number_col[i][j]=cnt++; //点编号 } if (isdigit(str[i][j][4])) { int t=(str[i][j][4]-'0')*100+(str[i][j][5]-'0')*10+str[i][j][6]-'0'; row_sum[i][j]=t; //保存下(i,j)位置表示的该列数字之和 number_row[i][j]=cnt++; } if (str[i][j][0]=='.') { col_cnt[j]++; //记录第j列空白格的数目 row_cnt[i]++; //记录第i行空白格的数目 number_w[i][j]=cnt++; //给空白格编号 } } } for (i=0;i<n;i++) { for (j=0;j<m;j++) { if (number_row[i][j]!=0) { int all=0,k=j+1; while (k>=0&&k<m&&number_w[i][k]) { all++; id[i][k]=num; //记录边的序号 addedge(number_row[i][j],number_w[i][k],8); //(i,j)位置和这一行后面的空白格连边 k++; } addedge(0,number_row[i][j],row_sum[i][j]-all); } if (number_col[i][j]!=0) { int all=0,k=i+1; while (k>=0&&k<n&&number_w[k][j]) { all++; addedge(number_w[k][j],number_col[i][j],8);//(i,j)位置和这一列下面的空白格连边 k++; } addedge(number_col[i][j],cnt,col_sum[i][j]-all); } } } } int main() { int i,j; while (~scanf("%d%d",&n,&m)) { init(); build(); int x=dinic(0,cnt,cnt+1); for (i=0;i<n;i++) { for (j=0;j<m;j++) { if (id[i][j]) printf("%d",9-edge[id[i][j]].cap); else printf("_"); if (j<m-1) printf(" "); else printf("\n"); } } } return 0; }
Kakuro Extension (hdu 3338 最大流 建图难)
标签:kakuro extension hdu 3338 最大流 建图难
原文地址:http://blog.csdn.net/u014422052/article/details/45133829