jzoj 1769 islands and bridge

来源:互联网 发布:程序员面试宝典5下载 编辑:程序博客网 时间:2024/06/05 15:42

Description

  给定一些岛屿和一些连接岛屿的桥梁,大家都知道汉密尔顿路是访问每个岛屿一次的路线,在我们这个地图中,每个岛屿有个正整数的权值,表示这个岛屿的观赏价值。假设一共有N个岛屿,用Vi表示岛屿Ci的价值,汉密尔顿路C1C2….Cn的价值是以下三部分的总和:
  (1)所有岛屿的价值之和;
  (2)对于路径中相邻的两个岛屿CiCi+1,把两个岛屿的价值之积加到总价值中;
  (3)路径中连续三个岛屿CiCi+1Ci+2,如果Ci与Ci+2有桥直接相连,则把这三个岛屿价值之积加到总价值中。
  要求计算汉密尔顿路最大的价值以及方案数。

Input

  输入第一行是一个整数Q(Q<=20),表示测试数据的数量。每个测试数据第一行输入两个整数N和M,分别表示岛屿数和桥梁数,接下来一行包含N个正整数,第i个数表示Vi,每个数不超过100,最后M行,每行两个数X,Y,表示岛X和岛Y之间有一座桥直接相连,桥是双向的,岛屿编号为1到N(N<=13)

Output

  对于每个测试数据,输出一行,两个整数,第一个数表示最大价值,第二个数表示方案数,如果不存在汉密尔顿路径,输出“0 0”
  注意:一条路径可以反着走,我们认为这两条路径是同一条路径。

Sample Input

2
3 3
2 2 2
1 2
2 3
3 1
4 6
1 2 3 4
1 2
1 3
1 4
2 3
2 4
3 4

Sample Output

22 3
69 1

Solution

不太熟悉c++的pascal选手表示心态爆炸。
一直有各种运算优先级的差异导致疯狂调试,终极爆炸。
状压专题*2
考虑定义一个状态f[i][j][k]
i为一个二进制状态,0,1表示选了或者没选,j,k则表示上两次所选的编号。
预处理一下f数组
考虑转移 很显然
枚举一个t f[i|(1<<(t-1))][k][t]=max(f[i][j][k]+a[t]+a[t]*a[k]+a[t]*a[k]*a[j](j,t相连))
调了很久很烦 下定决心掌握调试技巧

Code

```#include <cstdio>#include <cstring>#include <algorithm>#define fo(i,a,b) for (i=a;i<=b;i++)#define ll long longusing namespace std;ll map[25][25];ll f[9000][13][13],cnt[9000][13][13],a[20];int main(){    ll n,m,x,y,q,s,tt,h;    int i,j,k,t;    freopen("1.in","r",stdin);    freopen("1.out","w",stdout);    scanf("%lld",&tt);    while (tt) {        tt--;        scanf("%lld%lld",&n,&m);        memset(map,0,sizeof(map));        memset(f,0,sizeof(f));        memset(cnt,0,sizeof(cnt));        fo(i,1,n) scanf("%lld",&a[i]);        if (n==1) {            printf("%lld ",a[1]);            printf("1\n");            continue;        }        fo(i,1,m) {            scanf("%lld%lld",&x,&y);            map[x][y]=1,map[y][x]=1;        }        q=(1<<n)-1;          for (j=1;j<=n;j++)            for (k=1;k<=n;k++) {                if (j==k||!map[j][k]) continue;                x=1<<(j-1),y=1<<(k-1);                f[(x|y)][j][k]=a[k]*a[j]+a[k]+a[j];                cnt[(x|y)][j][k]=1;            }        fo(i,1,q) {          for (j=1;j<=n;j++) {            if ((i&(1<<(j-1)))==0) continue;            for (k=1;k<=n;k++) {              if ((!map[j][k])||(f[i][j][k]==0)) continue;              for (t=1;t<=n;t++) {                if ((!map[k][t])||((i&(1<<(t-1)))!=0)) continue;                //if ((i|(1<<(t-1)))>q) continue;                if (map[j][t]) s=a[j]*a[k]*a[t]; else s=0;                if (f[i+(1<<(t-1))][k][t]==(f[i][j][k]+s+a[t]+a[t]*a[k])) cnt[i+(1<<(t-1))][k][t]+=cnt[i][j][k];                    else if (f[i+(1<<(t-1))][k][t]<(f[i][j][k]+s+a[t]+a[t]*a[k])) cnt[i+(1<<(t-1))][k][t]=cnt[i][j][k];                f[i+(1<<(t-1))][k][t]=max(f[i+(1<<(t-1))][k][t],f[i][j][k]+s+a[t]+a[t]*a[k]);              //    cnt[i|(1<<(t-1))][j][k]=cnt[i][j][k]+h+cnt[i|(1<<(t-1))][j][k];              }        }    }      }     ll p=0;    ll ans=0;    for (i=1;i<=n;i++)      for (j=1;j<=n;j++)        if (i!=j) {        //  q=(1<<(j-1))|(1<<(i-1));            if (p<f[q][i][j]) {                p=f[q][i][j];                ans=cnt[q][i][j];            } else if (p==f[q][i][j]) ans+=cnt[q][i][j];        }    if (p==0) {        printf("0 0\n");        continue;    }    printf("%lld ",p);    printf("%lld\n",(ans/2));    }} 

(我的代码还是很丑呀)

原创粉丝点击