状态压缩dp

Fig 1

Fig 2

Figure 1 Figure 2

A police unit has dealt with a number of situations where they need to search multiple sites as rapidly as possible with a small group of officers. Figures 1 and 2 are diagrams for two situations.  Sites to search are labeled with capital letters.  The site labeled A is the common starting point.  Some of these locations have connecting paths.  Assume each connecting path takes one unit of time to traverse, and individual sites take no time for a visual search. 

Consider Figure 1.  If there are 3 or more officers it takes only one unit of time to search.  Different officers follow paths AB, AC, and AD.  If there are two officers, the complete search will take two time units.  For example one officer could follow the path ABC and the other AD.

Consider Figure 2.  If there were 3 officers, they could follow paths ABC, ABD, and AEAF and take 3 units of time.  With 2 officers they could follow paths ABCBD and AEAF, and take 4 units of time. 

These are simple enough examples to figure out by hand.  For more complicated arrangements they want your programming help.

Input

The input will consist of 1 to 25 data sets, followed by a line containing only 0.

A dataset is a single line starting with blank separated positive integers s n p, where s is the number of sites to search, n is the number of officers, and p is the number of connecting paths between search sites.  Limits are 2 ≤ s ≤ 10, 1 ≤ n ≤ 4, and p ≤ 20.  The rest of the line contains p pairs of capital letters, indicating paths between sites, each preceded by a blank.  Sites are labeled with the first s capital letters.  All sites will be connected by some sequence of connecting paths.  The two letters in each letter pair will be in increasing alphabetical order. No letter pair will be repeated. 

Output

here is one line of output for each data set, containing only the minimum search time for n officers starting at site A.

Take some care with your algorithm, or else your solution may take too long.

The sample input data sets correspond to the scenarios discussed. 

Sample Input

4 4 5 AB BC CD AD AC
4 2 5 AB BC CD AD AC
6 3 5 AB BC BD AE AF
6 2 5 AB BC BD AE AF 0

Sample Output

1
2
3
4
这个题是真心好题呀!可是我想不出来看的解题报告和标称后才知道怎么做,http://www.acdream.tk/problem.php?id=1090,以后在慢慢的体会吧
View Code
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[1050][10],f[20][20];
int a[1050],b[1050],c[1050];
int oo=1000000000;
void floyd(int n)
{
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(f[i][j]>f[i][k]+f[k][j]) f[i][j]=f[i][k]+f[k][j];
for(int t=0;t<1050;t++)
a[t]=b[t]=oo;
}
int min(int x,int y)
{
return x<y? x:y;
}
int max(int x,int y)
{
return x>y? x:y;
}
int main()
{
int s,n,p,i,j,k;
char str[3];
while(scanf("%d",&s)!=EOF){
if(!s) break;
scanf("%d%d",&n,&p);
for(i=0;i<s;i++){
for(j=0;j<s;j++)
f[i][j]=oo;
f[i][i]=0;
}
while(p--){
scanf("%s",str);
f[str[0]-'A'][str[1]-'A']=f[str[1]-'A'][str[0]-'A']=1;
}
floyd(s);//用floy算出s多源顶点到其他点的距离
for(i=0;i<(1<<s);i++)
for(j=0;j<s;j++)
dp[i][j]=oo;
for(i=1;i<s;i++)
dp[1<<(i-1)][i]=f[0][i];//A点到其他点的距离
for(i=1;i<(1<<(s-1));i++)这个感觉像一个完全背包,就是有一个人走的到情况的最优解
for(j=1;j<s;j++)
if(i&(1<<(j-1))){
for(k=1;k<s;k++){
if(i&(1<<(k-1))) continue;
dp[i|(1<<(k-1))][k]=min(dp[i|(1<<(k-1))][k],dp[i][j]+f[j][k]);
}
}

for(i=1;i<(1<<(s-1));i++){
for(j=1;j<s;j++)
a[i]=b[i]=min(a[i],dp[i][j]);
}
while(n>1) //相当于矩阵乘法,乘n次代表n个人走的最优解
{
memcpy(c,a,sizeof(a)); //c[i] 和 a[i] 相当于一个滚动数组
for(i=0;i<(1<<(s-1));i++)
a[i]=b[i];
for(i=1;i<(1<<(s-1));i++)
for(j=1;j<(1<<(s-1));j++)
{
a[i|j]=min(a[i|j],max(b[i],c[j]));
}
n--;
}
printf("%d\n",a[(1<<(s-1))-1]);

}
return 0;
}
接下来也是状态压缩dp,都是在图上

1175: A Tour Around Hangzhou

Time Limit: 2 Sec  Memory Limit: 128 MB
SUBMIT: 84  Solved: 22
[SUBMIT][STATUS]

Description

        swimming来到杭州旅行,杭州是个美丽的城市,有很多美丽的景点.但让他头痛的是这些景点之间都有很长的距离,swimming决定选择便宜快捷的公交作为交通工具.杭州的公交网也十分复杂,不同的景点之间要转很多次公交才能到达,已知这些公交都只能站点上下车,并且相同的两个站点之间可能会有多班公交车.swimming想让你帮他设计一条旅游线路,花最少的钱旅游完所有的景点,最后回到出发地.

Input

       输入有多组案例.

       对于每个案例,第一行包含3个数据,公交站点的个数n(1<=n<=10^4),公交线路数量m(1<=m<=10^5),景点数量k(k<15);接下来m行每行包括三个数据si,ei,vi(0<=si,ei<n 1<=vi<=100)表示有一班往返于站点si和ei之间的交通线路费用为vi;接下来一行包括k个小于n的整数,表示这些站点附近有景点,swimming必须到达这些站点;最后一行包含一个小于n的整数,表示swimming的出发地.

Output

       如果swimming能旅游完所有的景点并且最后回到出发地,输出swimming坐公交旅行的最低花费;如果不能,输出"What a pity"(不加引号).对于每个案例,输出占一行.

Sample Input

5 6 2
0 1 3
1 2 2
0 2 1
2 3 2
1 3 3
3 4 4
1 3 0

Sample Output

9
View Code
#include <cstdio>
#include<string.h>
#include<queue>
#include<algorithm>
#include <iostream>
#define MAXE 100005
#define MAXN 10005
#define INF 0x3fffffff
typedef long long ll;

using namespace std;
struct edge{
int v, w, n;
}e[MAXE*2];
int n, m, k, view[15];
int first[MAXN],es;
int map[16][16], d[15][40000],ans;
ll full;
int inq[MAXN], dis[MAXN];
void addedge(int u, int v, int w){
e[es].v = v;
e[es].w = w;
e[es].n = first[u];
first[u] = es++;
}
void spfa(int st){
queue<int> q;
for (int i = 0; i < n; i++) {
inq[i] = 0;
dis[i] = (i == st ? 0 : INF);
}
q.push(st);
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = 0;
for (int i = first[u]; i != -1; i = e[i].n) {
int v = e[i].v;
if (dis[v] > dis[u] + e[i].w) {
dis[v] = dis[u] + e[i].w;
if (!inq[v]) {
inq[v] = 1;
q.push(v);
}
}
}
}
}
int dfs(int p, ll stat){
if (d[p][stat] != -1) return d[p][stat];
if (stat == full) return d[p][stat] = map[p][0];
int ans = INF, tmp;
for(int i = 1; i <= k; i++){
if ((stat&((ll)1<<i)) == 0) {
tmp = dfs(i, stat ^ (1 << i));
if(tmp + map[p][i] < ans)ans = tmp + map[p][i];
}
// cout<<ans<<endl;
}
return d[p][stat] = ans;
}

int main(){
//freopen("F.in","r",stdin);
//freopen("F.out","w",stdout);
while (scanf("%d%d%d", &n, &m, &k)!=EOF) {
memset(first, -1, sizeof first);
es=0;
int ts, te, tv;
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &ts, &te, &tv);
addedge(ts, te, tv);
addedge(te, ts, tv);
}
for (int i = 1; i <= k; i++) {
scanf("%d", &view[i]);
}
scanf("%d", &view[0]);
memset(map, -1, sizeof map);
int hasway = 1;
for (int i = 0; i <= k && hasway; i++) {
spfa(view[i]);
for (int j = 0; j <=k && hasway; j++){
map[i][j] = dis[view[j]];
if (map[i][j] == INF) hasway = 0;
}
}


if (!hasway) {
printf("What a pity\n");
} else {
full=((ll)1<<(k+1))-2;
for(int i=0;i<=k;i++)for(ll j=0;j<=full;j++) d[i][j]=-1;
printf("%d\n",dfs(0, 0));
}

}
return 0;
}

posted on 2012-03-24 14:08  Goal  阅读(374)  评论(0编辑  收藏  举报

导航