【售货员的难题】
2016-10-30 22:15
323 查看
直接上搜索dfs
50分
但是,显然是可以剪枝的
加一条剪枝就90分。
然后下面有一个我比较迷的剪枝
感觉是错的。。
数据生成器:
还是容易造出数据卡。codevs数据水了。
但是基于它的这个思想。。
又有种优化法,优先队列..
没写,数据水能过。
下面有种预处理了一下的方法
我觉得还是很迷啊。。
果然对拍出错了。。
正解状压DP
上面都是正常解法。
//有的地方用min做数组要CE,请自行修改
//模拟退火是概率算法,要多交几次才能AC 2333
//期望得分70+ ~ 100-
#include<cstdio> #include<iostream> #include<ctime> using namespace std; #define N 20 int n,a ,ans=0x7ffffff; bool vis ;int tot; void dfs(int u,int res) { if(!res) { ans=min(ans,tot+a[u][1]); return; } for(int i=2;i<=n;i++) { if(!vis[i]) { vis[i]=true; tot+=a[u][i]; dfs(i,res-1); tot-=a[u][i]; vis[i]=false; } } } int main(){ cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j]; vis[1]=true; dfs(1,n-1); cout<<ans; return 0; }
50分
但是,显然是可以剪枝的
加一条剪枝就90分。
#include<cstdio> #include<iostream> #include<ctime> using namespace std; #define N 20 int n,a ,ans=0x7ffffff; bool vis ;int tot; void dfs(int u,int res) { if(tot>ans)return; if(!res) { ans=min(ans,tot+a[u][1]); return; } for(int i=2;i<=n;i++) { if(!vis[i]) { vis[i]=true; tot+=a[u][i]; dfs(i,res-1); tot-=a[u][i]; vis[i]=false; } } } int main(){ cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j]; vis[1]=true; dfs(1,n-1); cout<<ans; return 0; }
然后下面有一个我比较迷的剪枝
#include<cstdio> #include<iostream> #include<ctime> using namespace std; #define N 20 int n,a ,ans=0x7ffffff; bool vis ;int tot; void dfs(int u,int res) { if(tot>ans)return; if(!res) { ans=min(ans,tot+a[u][1]); return; } for(int i=2;i<=n;i++) { if(!vis[i]) { if(tot+a[u][i]>ans)return;//??? vis[i]=true; tot+=a[u][i]; dfs(i,res-1); tot-=a[u][i]; vis[i]=false; } } } int main(){ cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j]; vis[1]=true; dfs(1,n-1); cout<<ans; return 0; }
感觉是错的。。
数据生成器:
#!usr/bin/env python #-*- coding: utf-8 -*- import random import sys fp = open("data.in","w") sys.stdout = fp n = 12 print n for i in range(1,n+1): for j in range(1,n+1): print random.randint(1,1000), print
还是容易造出数据卡。codevs数据水了。
但是基于它的这个思想。。
又有种优化法,优先队列..
没写,数据水能过。
下面有种预处理了一下的方法
#include<iostream> #include<cstdio> using namespace std; int n,g[20][20],r[20][20],f[20],ans=0x7fffffff; void Dfs(int now,int sum,int dis) { if(dis+r[now][1]>=ans)return; if(dis>ans)return; if(sum==n) { ans=min(ans,dis+g[now][1]); return; } for(int i=1;i<=n;i++) if(f[i]==0) { f[i]=1;Dfs(i,sum+1,dis+g[now][i]);f[i]=0; } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&g[i][j]),r[i][j]=g[i][j]; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) r[i][j]=min(r[i][j],r[i][k]+r[j][k]); f[1]=1; Dfs(1,1,0); printf("%d\n",ans); return 0; }
我觉得还是很迷啊。。
果然对拍出错了。。
正解状压DP
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<deque> #include<algorithm> #include<cmath> using namespace std; const int size = 124500; int dp[23][size]; int map[23][23]; int main() { int n; scanf("%d",&n); for(int i = 1;i <= n;i ++) for(int j = 1;j <= n;j ++) scanf("%d",&map[i][j]); memset(dp,63,sizeof(dp)); dp[1][1] = 0; for(int i = 0;i <= (1 << n);i ++) { for(int j = 1;j <= n;j ++) { if(((1 << j-1) & i) == 0) { for(int k = 1;k <= n;k ++) { if(((1 << k-1) & i)) { dp[j][((1 << j-1) | i)] = min(dp[j][((1 << j-1) | i)],dp[k][i] + map[k][j]); } } } } } int ans = 2147483640; for(int i = 2;i <= n;i ++) { ans = min(ans,dp[i][(1<<n)-1] + map[i][1]); } printf("%d",ans); return 0; }
上面都是正常解法。
//有的地方用min做数组要CE,请自行修改
//模拟退火是概率算法,要多交几次才能AC 2333
//期望得分70+ ~ 100-
/*模拟退火*/ /*AC代码:0ms*/ #include <iostream> #include <ctime> #include <cstdlib> using namespace std; const int MAX=41; const int RANN=1000; const int RUNN=50; const int INF=99999999; int map[MAX][MAX],rpath[RANN][MAX],min[RANN],N; void adjust(int x[],int rn)//rn为调整次数 { int a,b; while(rn--) { a=rand()%(N-1)+1;//调整的位置 b=rand()%(N-1)+1; swap(x[a],x[b]); } } void get_map() { int i,j; for(i=1;i<=N;i++) for(j=1;j<=N;j++) scanf("%d",&map[i][j]); } void get_rpath()//产生RANN组初始数列 { int i,j; for(i=0;i<RANN;i++) { for(j=1;j<=N-1;j++) rpath[i][j]=j+1; adjust(rpath[i],N-1);//初始调整 min[i]=INF; } } void swap(int &x,int &y)//交换x,y { int t=x; x=y; y=t; } int get_dis(int x[])//返回路径长度 { int sum=0,i,p=1; for(i=1;i<=N-1;i++) { sum+=map[p][x[i]]; p=x[i]; } sum+=map[p][1]; return sum; } void numcpy(int x[],int y[]) { for(int i=1;i<=N-1;i++) x[i]=y[i]; } void get_ans() { int i,j,t=N-1,temp,p[41]; while(t--)//调整的范围递减 { for(i=0;i<RANN;i++)//遍历RanN组数据 { for(j=0;j<RUNN;j++)//对于每组做RunN次 { numcpy(p,rpath[i]);//因为每次都在原有的rpath[i]上改变 adjust(p,t); temp=get_dis(p); if(temp<min[i]) { numcpy(rpath[i],p);//更新rpath[i]; min[i]=temp; } } } } int ans=min[0]; for(i=1;i<RANN;i++) if(min[i]<ans) ans=min[i]; printf("%d\n",ans); } int main () { srand(time(0));//以时间为随机数种子产生随机数 while(scanf("%d",&N)!=EOF) { get_map(); get_rpath(); get_ans(); } return 0; }
相关文章推荐
- 售货员的难题
- codevs 2596 售货员的难题
- caioj1041:递归11(售货员的难题)
- 【状压DP】售货员的难题
- 售货员难题 状压dp
- P1171 售货员的难题
- 售货员的难题(luogu1171)
- 洛谷P1171 售货员的难题【状压DP】
- 售货员的难题
- 洛谷 P1171 售货员的难题 【状压dp】
- CODEVS 2596 售货员的难题
- 洛谷 P1171 售货员的难题 【状压dp】
- 售货员的难题
- Luogu 1171 售货员的难题(状态压缩动态规划)
- 售货员的难题(codevs 2596)
- 2596 售货员的难题
- codevs2596 售货员的难题(状压dp)
- codevs 2596 售货员的难题
- 洛谷P1171 售货员的难题
- P1171 售货员的难题