GDOI2014 拯救莫莉斯
问题描述
莫莉斯·乔是圣域里一个叱咤风云的人物,他凭借着自身超强的经济头脑,牢牢控制了圣域的石油市场。
圣域的地图可以看成是一个n*m的矩阵。每个整数坐标点(x , y)表示一座城市(1<=x<= n, 1<=y<=m)。两座城市间相邻的定义为:对于城市(Ax, Ay)和城市(Bx, By),满足(Ax - Bx)2 + (Ay - By)2 = 1。
由于圣域的石油贸易总量很大,莫莉斯意识到不能让每笔石油订购单都从同一个油库里发货。为了提高效率,莫莉斯·乔决定在其中一些城市里建造油库,最终使得每一个城市X都满足下列条件之一:
1.该城市X内建有油库,
2.某城市Y内建有油库,且城市X与城市Y相邻。
与地球类似,圣域里不同城市间的地价可能也会有所不同,所以莫莉斯想让完成目标的总花费尽可能少。如果存在多组方案,为了方便管理,莫莉斯会选择建造较少的油库个数。
输入格式
第一行两个正整数n,m ( n * m <= 50 且m<=n),表示矩阵的大小。
接下来一个n行m列的矩阵F,Fi, j表示在城市(i,j)建造油库的代价。
输出格式
输出两个数,建造方案的油库个数和方案的总代价。
输入样例: |
输出样例: |
3 3 6 5 4 1 2 3 7 8 9 |
3 6 |
数据范围
对于30%数据满足 n * m <= 25;
对于100%数据满足n * m <= 50; 0 <= Fi, j <= 100000
solution:
很简单的状压dp,然而考试的时候想成了网络流,f[i][j][k]表示到第i层上一层状态为j这一层状态为k的最小花费,
f[i+1][k][x]=min(f[i][j][k]+cost[i+1][x]);这个cost数组需要预处理出来,表示每一层每一个状态对应的花费,还有一个附加数组g[i][j][k],表示这个状态下的油库数量,最后答案为min(f[i+1][j][0])
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int read() { 7 int s=0,f=1; 8 char ch=getchar(); 9 while(ch>'9'||ch<'0') { 10 if(ch=='-') { 11 f=-1; 12 } 13 ch=getchar(); 14 } 15 while(ch>='0'&&ch<='9') { 16 s=(s<<1)+(s<<3)+(ch^48); 17 ch=getchar(); 18 } 19 return s*f; 20 } 21 int f[52][1<<7|1][1<<7|1],g[52][1<<7|1][1<<7|1]; 22 int sum[1<<7|1],n,m,val[52][52],cost[52][1<<7|1]; 23 int lowbit(int x) { 24 return x&(-x); 25 } 26 int get(int x) { 27 int ans=0; 28 while(x) { 29 x-=lowbit(x); 30 ans++; 31 } 32 return ans; 33 } 34 void init() { 35 for(int i=0; i<=(1<<m); i++) { 36 sum[i]=get(i); 37 } 38 for(int i=1; i<=n; i++) { 39 for(int j=0; j<(1<<m); j++) { 40 for(int k=1; k<=m; k++) { 41 if((1<<(k-1))&j) { 42 cost[i][j]+=val[i][k]; 43 } 44 } 45 } 46 } 47 memset(f,0x5f,sizeof(f)); 48 memset(g,0x5f,sizeof(g)); 49 for(int i=0; i<(1<<m); i++) { 50 f[1][0][i]=cost[1][i]; 51 g[1][0][i]=sum[i]; 52 } 53 } 54 void dp() { 55 for(int i=1; i<=n; i++) { 56 for(int j=0; j<(1<<m); j++) { //shangyiceng 57 for(int k=0; k<(1<<m); k++) { //benceng 58 if(f[i][j][k]>=1600085850) { 59 continue; 60 } 61 for(int x=0; x<(1<<m); x++) { 62 if(((x|j|k|(k<<1)|(k>>1))&((1<<m)-1))==((1<<m)-1)) { 63 if(f[i+1][k][x]>=f[i][j][k]+cost[i+1][x]) { 64 if(f[i+1][k][x]==f[i][j][k]+cost[i+1][x]) { 65 g[i+1][k][x]=min(g[i+1][k][x],g[i][j][k]+sum[x]); 66 } else { 67 g[i+1][k][x]=g[i][j][k]+sum[x]; 68 } 69 f[i+1][k][x]=f[i][j][k]+cost[i+1][x]; 70 } 71 } 72 } 73 } 74 } 75 } 76 } 77 struct node { 78 int f,g; 79 friend bool operator < (node a,node b) { 80 return (a.f==b.f)?(a.g<b.g):(a.f<b.f); 81 } 82 } proj[1<<7|1]; 83 int main() { 84 n=read(); 85 m=read(); 86 for(int i=1; i<=n; i++) { 87 for(int j=1; j<=m; j++) { 88 val[i][j]=read(); 89 } 90 } 91 init(); 92 dp(); 93 int ans_f=0x7fffffff,ans_g=0x7fffffff; 94 int kk=0; 95 for(int i=0; i<(1<<m); i++) { 96 if(f[n+1][i][0]<=ans_f) { 97 if(ans_f==f[n+1][i][0]) { 98 ans_g=min(ans_g,g[n+1][i][0]); 99 } else { 100 ans_g=g[n+1][i][0]; 101 } 102 ans_f=f[n+1][i][0]; 103 } 104 } 105 cout<<ans_g<<" "<<ans_f; 106 return 0; 107 }