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 }

 

posted @ 2017-08-07 06:31  Forever_goodboy  阅读(175)  评论(0编辑  收藏  举报