P5911 [POI2004]PRZ 题解

N=16,首先考虑将其作为状压维度

可以用其来记录哪一些人已经渡河,哪一些人没有渡河。

每一次状态转移就是一次渡河,可以暴力枚举本次渡河的人是哪一些。

利用记忆化搜索可以更好地实现这个过程。

在枚举上一个合法状态的时候可以利用枚举子集的方式来完成,以此降低一部分复杂度。实际上枚举子集的复杂度依然是2^n

更新:枚举子集的总复杂度为3^n

枚举子集的方法看其他blog

代码如下

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 inline int r()
 7 {
 8     int s=0,k=1;char c=getchar();
 9     while(!isdigit(c))
10     {
11         if(c=='-')k=-1;
12         c=getchar();
13     }
14     while(isdigit(c))
15     {
16         s=s*10+c-'0';
17         c=getchar();
18     }
19     return s*k;
20 }
21 int m,n,t[20],w[20],f[66666],chk[66666],cst[66666];
22 bool check(int x)
23 {
24     //if(chk[x]!=-1)return chk[x];
25     int now=0,nd=0;
26     while(x)
27     {
28         now++;
29         if(x&1)nd+=w[now];
30         if(nd>m)return chk[x]=0;
31         x>>=1;
32     }
33     return chk[x]=1;
34 }
35 int cost(int x)
36 {
37     //if(cst[x]!=-1)return cst[x];
38     int now=0,nd=0;
39     while(x)
40     {
41         now++;
42         if(x&1)nd=max(nd,t[now]);
43         x>>=1;
44     }
45     return cst[x]=nd;
46 }
47 int dfs(int state)
48 {
49     if(!state)return 0;
50     if(f[state])return f[state];
51     int mini=1e9;
52     for(int i=state;i;i=(i-1)&state)
53     if(check(i))
54     {
55         mini=min(mini,dfs(state^i)+cost(i));
56     }
57 //    cout<<"state: "<<state<<" "<<mini<<endl;
58     return f[state]=mini;
59 }
60 int main()
61 {
62     memset(chk,-1,sizeof(chk));
63     memset(cst,-1,sizeof(cst));
64     m=r();n=r();
65     for(int i=1;i<=n;i++)
66     {
67         t[i]=r();
68         w[i]=r();
69     }
70     for(int i=1;i<=n;i++)
71     f[1<<(i-1)]=t[i];
72     for(int i=1;i<=n;i++)
73     for(int j=1;j<=n;j++)
74     {
75         if(i!=j)
76         {
77             int tmp=(1<<(i-1))|(1<<(j-1));
78             if(check(tmp))f[tmp]=cost(tmp);
79             else f[tmp]=t[i]+t[j];
80         }
81     }
82     cout<<dfs((1<<n)-1);
83 }

 

posted @ 2021-07-11 21:11  lei_yu  阅读(56)  评论(0编辑  收藏  举报