拯救莫莉斯

问题描述

莫莉斯·乔是圣域里一个叱咤风云的人物,他凭借着自身超强的经济头脑,牢牢控制了圣域的石油市场。

圣域的地图可以看成是一个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

考试的时候吧n*m=50 看成n,m<=50了,结果想了半天网络流......

正解是状压  以为m最大是7

f[i][j][k]:到了第i行 前一个i-1行状态为j,i行状态为k

 从当前往后推 f[i+1][k][x]=min(f[i][j][k]+cost[i+1][x])   ( j|k|x|(k<<1)|(k>>1) )&maxp==maxp

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #define mem(a,b) memset(a,b,sizeof(a))
 5 using namespace std;
 6 const int N=(1<<7)+30;
 7 inline int minn(int a,int b){return a<b?a:b;}
 8 
 9 int n,m,maxp,ans,sum;
10 int v[56][56],cost[56][N],num[56][N];
11 int f[56][N][N],g[56][N][N];
12 //f:代价 g:数目 
13 void chu()
14 {
15     for(int i=1;i<=n;++i)
16         for(int j=0;j<=maxp;++j)
17           for(int k=1;k<=m;++k)
18                 if((1<<(k-1))&j)
19                 {
20                   cost[i][j]+=v[i][k];
21                   ++num[i][j];
22                 }
23 }
24 
25 void out11()
26 {
27     printf("\n");
28     for(int i=1;i<=n;++i)
29     {
30       for(int j=0;j<=maxp;++j)
31         for(int k=0;k<=maxp;++k)
32           cout<<f[i][j][k]<<' ';
33       printf("\n");
34     }
35     printf("\n");
36 }
37 
38 int main(){
39     //freopen("1.txt","r",stdin);
40     //freopen("proj7.in","r",stdin);
41     scanf("%d%d",&n,&m);
42     maxp=(1<<m)-1;
43     for(int i=1;i<=n;++i)
44       for(int j=1;j<=m;++j)
45         scanf("%d",&v[i][j]);
46     chu();
47     mem(f,0x7f);mem(g,0x7f);
48     for(int i=0;i<=maxp;++i)
49     {
50       f[1][0][i]=cost[1][i];
51       g[1][0][i]=num[1][i];
52     }
53     for(int i=1;i<=n;++i)
54       for(int j=0;j<=maxp;++j)
55         for(int k=0;k<=maxp;++k)
56           for(int l=0;l<=maxp;++l)
57           {
58               if( ((j|k|l|(k<<1)|(k>>1))&maxp)==maxp )
59               {
60                         //if(i==2&&j==0&&k==maxp&&l==0)system("pause");
61                         if(f[i+1][k][l]>f[i][j][k]+cost[i+1][l])
62                         {
63                             f[i+1][k][l]=f[i][j][k]+cost[i+1][l];
64                             g[i+1][k][l]=g[i][j][k]+num[i+1][l];
65                         }
66                         else
67                           if(f[i+1][k][l]==f[i][j][k]+cost[i+1][l])
68                               g[i+1][k][l]=minn(g[i+1][k][l],g[i][j][k]+num[i+1][l]);
69                     }
70                 }
71     
72     //cout<<f[2][0][maxp]<<endl;
73     //cout<<f[3][maxp][0];
74     //out11();
75     ans=0x7fffffff;
76     sum=0x7fffffff;
77     for(int i=0;i<=maxp;++i)
78     {
79         if(ans>f[n+1][i][0])
80         {
81             ans=f[n+1][i][0];
82             sum=g[n+1][i][0];
83         }
84         else
85           if(ans==f[n+1][i][0])
86             sum=minn(sum,g[n+1][i][0]);
87         //printf("ans=%d sum=%d\n",ans,sum);
88     }
89     printf("%d %d",sum,ans);
90     //while(1);
91     return 0;
92 }
code

 

posted @ 2017-08-06 19:50  A_LEAF  阅读(218)  评论(0编辑  收藏  举报