COJ 0501 取数游戏(TPM)

取数游戏(TPM)
难度级别:D; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

给你一个n*n的格子的棋盘,每个格子里面有一个非负数。从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能有公共边,并且取出的数的和最大。(二分图匹配练习)

输入
第一行是一个正整数n (n<20)。
接下来是 n*n 个非负数。
输出
输出可能取得的最大的和。
输入示例
3
5 9 4
8 3 6
2 7 1
输出示例
30
其他说明
n<20

题解:“没有公共边”这是赤裸裸的二分图呀!随便按(i+j)&1造个二分图跑了就行。。。

而且,这是我第一个接触的构造题吧= = 还是非常有纪念意义的= =我记得当年还是小健建给我亲自敲了一遍DInic然后敲了一遍这道题。。。回忆满满呢~

现在老练的ISAP+缩行:

 1 //这两道题有什么区别。。。= =
 2 #include<iostream>   
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<cstring>
 8 using namespace std;
 9 const int maxn=2002+10,maxm=80002+10,inf=-1u>>1;
10 struct ISAP{
11     struct tedge{int x,y,w,next;}adj[maxm];int ms,fch[maxn];
12     int d[maxn],s[maxn],cur[maxn],gap[maxn],n,top;
13     void init(int n){
14         this->n=n;ms=0;top=0;
15         memset(d,-1,sizeof(d));
16         memset(fch,-1,sizeof(fch));
17         return;
18     }
19     void addedge(int u,int v,int w){
20         adj[ms]=(tedge){u,v,w,fch[u]};fch[u]=ms++;
21         adj[ms]=(tedge){v,u,0,fch[v]};fch[v]=ms++;
22         return;
23     }
24     void bfs(){
25         queue<int>Q;Q.push(n);d[n]=0;
26         while(!Q.empty()){
27             int u=Q.front();Q.pop();
28             for(int i=fch[u];i!=-1;i=adj[i].next){
29                 int v=adj[i].y;
30                 if(d[v]==-1) d[v]=d[u]+1,Q.push(v);
31             }
32         } return;
33     }
34     int maxflow(int S,int T){
35         n=T;bfs();int k=S,i,flow=0;
36         for(i=0;i<=n;i++) cur[i]=fch[i],gap[d[i]]++;
37         while(d[S]<n){
38             if(k==n){
39                 int mi=inf,pos;
40                 for(i=0;i<top;i++) if(adj[s[i]].w<mi) mi=adj[s[i]].w,pos=i;
41                 for(i=0;i<top;i++) adj[s[i]].w-=mi,adj[s[i]^1].w+=mi;
42                 flow+=mi;top=pos;k=adj[s[top]].x;
43             }
44             for(i=cur[k];i!=-1;i=adj[i].next){
45                 int v=adj[i].y;
46                 if(adj[i].w&&d[k]==d[v]+1){cur[k]=i;k=v;s[top++]=i;break;}
47             }
48             if(i==-1){
49                 int lim=n;
50                 for(i=fch[k];i!=-1;i=adj[i].next){
51                     int v=adj[i].y;
52                     if(adj[i].w&&d[v]<lim) lim=d[v],cur[k]=i;
53                 } if(--gap[d[k]]==0) break;
54                 d[k]=lim+1;gap[d[k]]++;
55                 if(k!=S) k=adj[s[--top]].x;
56             }
57         } return flow;
58     }
59 }sol;
60 inline int read(){
61     int x=0,sig=1;char ch=getchar();
62     while(!isdigit(ch)){if(ch=='-') sig=-1;ch=getchar();}
63     while(isdigit(ch)) x=10*x+ch-'0',ch=getchar();
64     return x*=sig;
65 }
66 inline void write(int x){
67     if(x==0){putchar('0');return;}if(x<0) putchar('-'),x=-x;
68     int len=0,buf[15];while(x) buf[len++]=x%10,x/=10;
69     for(int i=len-1;i>=0;i--) putchar(buf[i]+'0');return;
70 }
71 int A[21][21],mx[]={1,-1,0,0},my[]={0,0,-1,1};
72 void init(){
73     int n=read();long long ans=0;
74     sol.init(n*n+2);int S=n*n+1,T=n*n+2;
75     for(int i=1;i<=n;i++)
76        for(int j=1;j<=n;j++){
77                A[i][j]=read();
78             if((i+j)&1){
79                sol.addedge(S,i*n+j-n,A[i][j]);
80                for(int d=0;d<4;d++){
81                    int nx=i+mx[d],ny=j+my[d];
82                    if(nx>=1&&nx<=n&&ny>=1&&ny<=n) sol.addedge(i*n+j-n,nx*n+ny-n,inf);
83                }
84            }
85            else sol.addedge(i*n+j-n,T,A[i][j]);
86            ans+=A[i][j];
87        } 
88     write(ans-sol.maxflow(S,T));
89     return;
90 }
91 void work(){
92     return;
93 }
94 void print(){
95     return;
96 }
97 int main(){
98     init();work();print();return 0;
99 }

当时最稚嫩的代码。。。真的有种说不出的感动:

  1 #include <iostream>
  2 #include <queue>
  3 using namespace std;
  4 
  5 const int maxn = 400 + 10;
  6 const int maxm = 10000 + 10;
  7 
  8 struct Edge
  9 {
 10     int from, to, cap, flow;
 11 };
 12 
 13 struct Dinic
 14 {
 15     int n, m, s, t;
 16     int first[maxn], next[maxm];
 17     
 18     Edge edges[maxm];
 19     
 20     void init(int n)
 21     {
 22         this -> n = n;
 23         m = 0;
 24         
 25         memset(first, -1, sizeof(first));
 26         
 27         return ;
 28     }
 29     
 30     void AddEdge(int from, int to, int cap)
 31     {
 32         edges[m] = (Edge){from, to, cap, 0};
 33         next[m] = first[from];
 34         first[from] = m++;
 35         
 36         edges[m] = (Edge){to, from, 0, 0};
 37         next[m] = first[to];
 38         first[to] = m++;
 39         
 40         return ;
 41     }
 42     
 43     int d[maxn], cur[maxn];
 44     bool vis[maxn];
 45     
 46     int BFS()
 47     {
 48         memset(vis, 0, sizeof(vis));
 49         queue<int> Q;
 50         
 51         Q.push(s);
 52         vis[s] = true;
 53         d[s] = 0;
 54         
 55         
 56         
 57         while(!Q.empty())
 58         {
 59             int x = Q.front(); Q.pop();
 60             
 61             for(int i = first[x]; i != -1; i = next[i])
 62             {
 63                 Edge& e = edges[i];
 64                 if(!vis[e.to] && e.cap > e.flow)
 65                 {
 66                     vis[e.to] = true;
 67                     d[e.to] = d[x] + 1;
 68                     Q.push(e.to);
 69                 }
 70             }
 71         }
 72             
 73         return vis[t];
 74     }
 75     int DFS(int x, int a)
 76     {
 77         if(x == t || !a) return a;
 78         
 79         int f, flow = 0;
 80         
 81         for(int& i = cur[x]; i != -1; i = next[i])
 82         {
 83             Edge& e = edges[i];
 84             if(d[e.to] == d[x] + 1 && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0)
 85             {
 86                 flow += f;
 87                 a -= f;
 88                 e.flow += f;
 89                 edges[i ^ 1].flow -= f;
 90                 if(!a) break;
 91             }
 92         }
 93         return flow;
 94     }
 95     
 96     
 97     int MaxFlow(int s, int t)
 98     {
 99         this -> s = s;
100         this -> t = t;
101         
102         int flow = 0;
103         
104         while(BFS())
105         {
106             for(int i = 0; i < n; i++) cur[i] = first[i];
107             flow += DFS(s, 1000000000);
108         }
109         return flow;   //你大爷!!!!!!!!!!!!!!!! 
110     }
111 }sol;
112 
113 int a[21][21];
114 int nx[] = {0, 0, -1, 1};
115 int ny[] = {-1, 1, 0, 0};
116 
117 int main()
118 {
119     int n, m;
120     scanf("%d", &n);
121     
122     m = n;
123     
124     sol.init(n * m + 2);
125     
126     long long double tot = 0;
127     
128     int s = n * m;
129     int t = n * m + 1;
130     
131     for(int i = 0; i < n; i++)
132       for(int j = 0; j < m; j++)
133       {
134           scanf("%d", &a[i][j]);
135           tot += a[i][j];
136           if((i + j) & 1)
137           {
138               sol.AddEdge(s, i * m + j, a[i][j]);
139               
140               
141               for(int d = 0; d < 4; d++)
142               {
143                   int mx = nx[d] + i;
144                   int my = ny[d] + j;
145                   
146                   if(mx >= 0 && mx < n && my >= 0 && my < m)
147                   {
148                       sol.AddEdge(i * m + j, mx * m + my, 2000000000);
149                   }
150               }
151           }
152           else sol.AddEdge(i * m + j, t, a[i][j]);
153       }
154       
155     printf("%d
", tot - sol.MaxFlow(s, t)); 156     
157     //system("pause");
158     return 0;
159 }
原文地址:https://www.cnblogs.com/chxer/p/4542665.html