记忆化搜索: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; }