记忆化搜索:s[status][cur] 记录在当前状态下,此刻位于cur点,到目的地所要的花费,由于一旦状态和位置确定,这个值是一定的
二进制状态表示:注意到n,m都比较小,由此启发
有一个剪枝:防止impossible时与目的地不连通而产生无限循环,
有m条边,对于每条边,最多存放在m个环中,故为m*m
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
using namespace std;
#define INF 10000000
struct pp
{
int b,c,p,r;
pp()
{
b=c=p=r=0;
}
pp(int _b,int _c,int _p,int _r)
{
b=_b;c=_c;p=_p;r=_r;
}
};
int n,m;
int vis[2500][11];
int s[2500][11];
vector<pp>vec[100];
int min(int aa,int bb)
{
return aa<bb?aa:bb;
}
int ans;
int renew(int status,int pos)
{
return status|(1<<(pos-1));
}
bool isvis(int status ,int pos)
{
return status&(1<<(pos-1));
}
int dfs(int cur,int status,int cost)
{
if(s[status][cur]!=-1)
return s[status][cur];
if(cur==n)
return 0;
vis[status][cur]++;
int tt,sstatus,temp;
int ret=INF;
if(vis[status][cur]>m*m)
return INF;
for(int i=0;i<vec[cur].size();++i)
{
tt=INF;sstatus=renew(status,vec[cur][i].b);
if(isvis(status,vec[cur][i].c))
tt=dfs(vec[cur][i].b,sstatus,cost+vec[cur][i].p);
temp=dfs(vec[cur][i].b,sstatus,cost+vec[cur][i].r);
if(tt<temp)
s[sstatus][vec[cur][i].b]=tt;
else
s[sstatus][vec[cur][i].b]=temp;
if(tt+vec[cur][i].p<temp+vec[cur][i].r)
ret=min(ret,tt+vec[cur][i].p);
else ret=min(ret,temp+vec[cur][i].r);
}
return ret;
}
int main ()
{
//freopen("aa.txt","r",stdin);
//freopen("bb.txt","w",stdout);
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<=n;++i)
vec[i].clear();
int a,b,c,p,r;
for(int i=1;i<=m;++i)
{
scanf("%d%d%d%d%d",&a,&b,&c,&p,&r);
vec[a].push_back(pp(b,c,p,r));
}
ans=INF;
memset(vis,0,sizeof(vis));
memset(s,-1,sizeof(s));
ans=dfs(1,1,0);
if(ans>=INF)
printf("impossible\n");
else
printf("%d\n",ans);
}
//system("pause");
return 0;
}
后来研究出更简洁的代码,因为参考了网上的代码,但发现这是错的
网上有人用了个强剪枝 vis[cur]>3 ,即不允许在同一条1-n的走的路径上走过一个环3次,
但下面这组数据程序就过不了,虽然在poj上过了
6 9
1 2 1 1 1
2 1 2 1 1
1 3 2 1 100
3 1 3 1 1
1 4 3 1 100
4 1 4 1 1
1 5 4 1 100
5 1 5 1 1
1 6 5 1 100
所以应该 vis[cur]>m*m
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
using namespace std;
#define INF 10000000
struct pp
{
int b,c,p,r;
pp()
{
b=c=p=r=0;
}
pp(int _b,int _c,int _p,int _r)
{
b=_b;c=_c;p=_p;r=_r;
}
};
int n,m,ans,vis[15];
bool flag;
vector<pp>vec[100];
int min(int aa,int bb)
{
return aa<bb?aa:bb;
}
void dfs(int cur,int cost)
{
if(cost>=ans||vis[cur]>m*m)
return ;
if(cur==n)
{
flag=true;
ans=cost;
return;
}
vis[cur]++;
for(int i=0;i<vec[cur].size();++i)
{
if(vis[vec[cur][i].c])
dfs(vec[cur][i].b,cost+vec[cur][i].p);
dfs(vec[cur][i].b,cost+vec[cur][i].r);
}
vis[cur]--;
}
int main ()
{
//freopen("aa.txt","r",stdin);
//freopen("bb.txt","w",stdout);
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<=n;++i)
vec[i].clear();
int a,b,c,p,r;
for(int i=1;i<=m;++i)
{
scanf("%d%d%d%d%d",&a,&b,&c,&p,&r);
vec[a].push_back(pp(b,c,p,r));
}
ans=INF;flag=false;
memset(vis,0,sizeof(vis));
dfs(1,0);
if(ans>=INF)
printf("impossible\n");
else
printf("%d\n",ans);
}
system("pause");
return 0;
}