A*算法
A*算法其实就是估价函数来优化搜索什么的,关键是估价函数的构建。
dij跑一遍bfs跑一遍即可。显然估价函数可以是由终点跑向各个点的最短路
#include<bits/stdc++.h> #include<iostream> #include<iomanip> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<queue> #include<deque> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> #include<bitset> #include<cmath> #include<cstdlib> #define INF 2147483642 using namespace std; inline long long read() { long long x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void put(long long x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; long long num=0;char ch[50]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } priority_queue<pair<int,int> > q; const long long MAXN=10002; long long n,m,k; long long lin[MAXN],nex[MAXN],ver[MAXN],e[MAXN],len=0; long long clin[MAXN],cnex[MAXN],cver[MAXN],ce[MAXN],clen=0; int d[MAXN],vis[MAXN],ans[MAXN],cnt=0; void add(long long x,long long y,long long z) { ver[++len]=y; nex[len]=lin[x]; lin[x]=len; e[len]=z; } void cadd(int x,int y,int z) { cver[++clen]=y; cnex[clen]=clin[x]; clin[x]=clen; ce[clen]=z; } void dij(int x) { for(int i=1;i<=n;i++)d[i]=INF; memset(vis,0,sizeof(vis)); q.push(make_pair(0,x)); d[x]=0; while(q.size()!=0) { int te=q.top().second; q.pop(); if(vis[te]==1)continue; vis[te]=1; for(int i=clin[te];i;i=cnex[i]) { int tn=cver[i]; if(d[tn]>d[te]+ce[i]) { d[tn]=d[te]+ce[i]; q.push(make_pair(-d[tn],tn)); } } } } void bfs() { memset(ans,-1,sizeof(ans)); q.push(make_pair(-d[n],n)); while(q.size()!=0) { int te=q.top().second; int v=-q.top().first; q.pop(); if(te==1) { ans[++cnt]=v-d[te]; if(cnt==k)return; continue; } for(int i=lin[te];i;i=nex[i]) { int tn=ver[i]; q.push(make_pair(-(v-d[te]+e[i]+d[tn]),tn)); } } } int main() { //freopen("1.in","r",stdin); n=read();m=read();k=read(); for(long long i=1;i<=m;i++) { long long x,y,z; x=read();y=read();z=read(); add(max(x,y),min(x,y),z); cadd(min(x,y),max(x,y),z); } dij(1); bfs(); for(int i=1;i<=k;i++)put(ans[i]); return 0; }
输出14 但是要注意细节和对第k短路的理解!(和上一道题相同的套路)
#include<iostream> #include<iomanip> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<queue> #include<deque> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> #include<bitset> #include<cmath> #include<cstdlib> #define INF 2147483646 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void put(int x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; int num=0;char ch[50]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } priority_queue<pair<int,int> > q; const int MAXN=100002; int n,m; int lin[MAXN],nex[MAXN],ver[MAXN],e[MAXN],len=0; int clin[MAXN],cnex[MAXN],cver[MAXN],ce[MAXN],clen=0; int s1,s2,k,cnt=0,ans=-1; int g[MAXN],d[MAXN],vis[MAXN]; void add(int x,int y,int z) { ver[++len]=y; nex[len]=lin[x]; lin[x]=len; e[len]=z; } void cadd(int x,int y,int z) { cver[++clen]=y; cnex[clen]=clin[x]; clin[x]=clen; ce[clen]=z; } void dij(int x) { for(int i=1;i<=n;i++)d[i]=INF; memset(vis,0,sizeof(vis)); d[x]=0;q.push(make_pair(0,x)); while(q.size()!=0) { int te=q.top().second; q.pop(); if(vis[te]==1)continue; vis[te]=1; for(int i=clin[te];i;i=cnex[i]) { int tn=cver[i]; if(d[tn]>d[te]+ce[i]) { d[tn]=d[te]+ce[i]; q.push(make_pair(-d[tn],tn)); } } } } void bfs() { if(s1==s2)k++;//敲黑板注意!细节! q.push(make_pair(-g[s1],s1)); while(q.size()!=0) { int te=q.top().second; int v=-q.top().first; q.pop(); if(te==s2) { cnt++; if(cnt==k){ans=v-g[te];return;} } for(int i=lin[te];i;i=nex[i]) { int tn=ver[i]; q.push(make_pair(-(v-g[te]+e[i]+g[tn]),tn)); } } } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=m;i++) { int x,y,z; x=read();y=read();z=read(); add(x,y,z);cadd(y,x,z); } s1=read();s2=read();k=read(); dij(s2); if(d[s1]==INF){put(ans);return 0;} for(int i=1;i<=n;i++)g[i]=d[i]; bfs(); put(ans); return 0; }
这道题A*、其实更像IDA*(IDA:迭代加深)
估计价值和具体细节不好想。代码之中。每次都和最优状态进行比较的出最优价值.
#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<ctime> #include<algorithm> #include<queue> #include<vector> #include<deque> #include<set> #include<stack> #include<bitset> #include<map> #include<cstdlib> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void put(int x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; int num=0;char ch[50]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } const int MAXN=6; int dx[9]={0,1,-1,1,-1,2,-2,2,-2}; int dy[9]={0,2,-2,-2,2,1,-1,-1,1}; int a[MAXN][MAXN]= { 0,0,0,0,0,0, 0,1,1,1,1,1, 0,0,1,1,1,1, 0,0,0,2,1,1, 0,0,0,0,0,1, 0,0,0,0,0,0, }; int b[MAXN][MAXN]; int t,n=5,m=5,s,s1; int flag=0,maxx=15; int ans=-1; char ch; int check() { int cnt=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) if(b[i][j]!=a[i][j])cnt++; } return cnt;//注意价值的估计 } void dfs(int depth,int x,int y,int p) { if(flag==1)return; if(depth==p) { if(check()==0)ans=depth,flag=1; return; } for(int i=1;i<=8;i++) { int xx=x+dx[i]; int yy=y+dy[i]; if(xx<=0||yy<=0||xx>n||yy>m)continue; //int u=check(); swap(b[x][y],b[xx][yy]); //if(u+depth-1<=p)dfs(depth+1,xx,yy,p);是等效的! if(check()+depth<=p)dfs(depth+1,xx,yy,p); //因为最后一步一定是check直接减2这里不需再+1. //对!就是因为最后一步是可以直接减2的加1的话限制了状态 swap(b[x][y],b[xx][yy]); } } int main() { //freopen("1.in","r",stdin); t=read(); while(t--) { flag=0;ans=-1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cin>>ch; if(ch=='1')b[i][j]=1; if(ch=='0')b[i][j]=0; if(ch=='*')b[i][j]=2,s=i,s1=j; } //for(int i=1;i<=n;i++){for(int j=1;j<=m;j++)cout<<b[i][j]<<' ';cout<<endl;} for(int i=0;i<=maxx;i++){if(flag==0)dfs(0,s,s1,i);else break;} put(ans); } return 0; }
如果不采用迭代加深搜索的话,直接爆搜只有50分。可能是我的只加了一个可行性剪枝。不够,不想思考剪枝了。
爆搜代码(其实和迭代加深搜索差不多):
#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<ctime> #include<algorithm> #include<queue> #include<vector> #include<deque> #include<set> #include<stack> #include<bitset> #include<map> #include<cstdlib> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void put(int x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; int num=0;char ch[50]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } const int MAXN=6; int dx[9]={0,1,-1,1,-1,2,-2,2,-2}; int dy[9]={0,2,-2,-2,2,1,-1,-1,1}; int a[MAXN][MAXN]= { 0,0,0,0,0,0, 0,1,1,1,1,1, 0,0,1,1,1,1, 0,0,0,2,1,1, 0,0,0,0,0,1, 0,0,0,0,0,0, }; int b[MAXN][MAXN]; int t,n=5,m=5,s,s1; int flag=0,maxx=15; int ans=200,p=15; char ch; int check() { int cnt=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) if(b[i][j]!=a[i][j])cnt++; } return cnt;//注意价值的估计 } void dfs(int depth,int x,int y) { if(depth>p)return; if(depth>=ans)return; if(check()==0)ans=min(depth,ans),flag=1; for(int i=1;i<=8;i++) { int xx=x+dx[i]; int yy=y+dy[i]; if(xx<=0||yy<=0||xx>n||yy>m)continue; swap(b[x][y],b[xx][yy]); if(check()+depth<=p)dfs(depth+1,xx,yy); swap(b[x][y],b[xx][yy]); } } int main() { //freopen("1.in","r",stdin); t=read(); while(t--) { flag=0;ans=200; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cin>>ch; if(ch=='1')b[i][j]=1; if(ch=='0')b[i][j]=0; if(ch=='*')b[i][j]=2,s=i,s1=j; } //for(int i=1;i<=n;i++){for(int j=1;j<=m;j++)cout<<b[i][j]<<' ';cout<<endl;} dfs(0,s,s1); if(flag==0)ans=-1; put(ans); } return 0; }
因为是一条路走到黑,所以没有限定层数的话会在不是正确解的地方浪费大量时间。
所以迭代加深枚举答案的范围就有很大的优越性了。值得注意!
这个就是和前面的搜索不太像了,原本我想的还是爆搜结果打脸了,估价函数是写出来了,但是显然dfs是不正确的因为不知道答案在第几层或者
搜到一个状态却没有可以达到这个状态的最优解。什么的一大堆,判重也不好判,状态的携带也会浪费大量时间所以不能用dfs。
优先bfs+A*即可。(不知道答案在第几层这样明显最优其实和IDA*差不多)
但注意要加map判重,出现过的最优状态不必要以不优的状态再次出现。
#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<ctime> #include<algorithm> #include<queue> #include<vector> #include<deque> #include<set> #include<stack> #include<bitset> #include<map> #include<cstdlib> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void put(int x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; int num=0;char ch[50]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } priority_queue<pair<int,pair<int,int> > > q; int a[4][4]= { 0,0,0,0, 0,1,2,3, 0,8,0,4, 0,7,6,5, }; map<int,int>f; struct wy { int x,y; }t[10]; int b[4][4],n=1,m=0,s1,s2,an,contrast;//vt 对比 使对照 char ch[10]; int dx[5]={0,1,-1,0,0}; int dy[5]={0,0,0,1,-1}; int len,ans,k1,k2; void prepare() { for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) t[a[i][j]].x=i,t[a[i][j]].y=j; } int check(int d[][4]) { int cnt=0; for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) { cnt+=abs(t[d[i][j]].x-i)+abs(t[d[i][j]].y-j); } return cnt; } int compress(int c[][4])//压缩 vt { int cnt=0; for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) cnt=cnt*10+c[i][j]; return cnt; } void unfold(int cnt,int c[][4])//展开 vt { int u=3,u1=3; for(int i=1;i<=9;i++) { if(u1==0)u1=3,u--; if(cnt%10==0)k1=u,k2=u1; c[u][u1--]=cnt%10; cnt/=10; } } void bfs() { q.push(make_pair(-check(b),make_pair(check(b),an))); //cout<<an<<endl;cout<<check()<<endl; while(q.size()!=0) { int v=-q.top().first; int v1=q.top().second.first; int value=q.top().second.second; q.pop();v-=v1; //cout<<value<<endl; if(value==contrast){ans=v;return;} int d[4][4]; unfold(value,d); for(int i=1;i<=4;i++) { int xx=k1+dx[i]; int yy=k2+dy[i]; if(xx<=0||yy<=0||xx>3||yy>3)continue; swap(d[k1][k2],d[xx][yy]); int sum=compress(d); if(f[sum]!=1)q.push(make_pair(-(v+1+check(d)),make_pair(check(d),sum))); f[sum]=1; swap(d[k1][k2],d[xx][yy]); } //for(int i=1;i<=3;i++){for(int j=1;j<=3;j++)cout<<d[i][j]<<' ';puts("");} } } int main() { //freopen("1.in","r",stdin); scanf("%s",ch+1); len=strlen(ch+1); for(int i=1;i<=len;i++) { if(m==3)m=0,n++; b[n][++m]=ch[i]-'0'; if(ch[i]=='0')s1=n,s2=m; an=an*10+ch[i]-'0'; } //cout<<an<<endl; prepare(); contrast=compress(a);//cout<<contrast<<endl; //int d[4][4]; //unfold(an,d);for(int i=1;i<=3;i++){for(int j=1;j<=3;j++)cout<<d[i][j]<<' ';puts("");}cout<<k1<<' '<<k2<<endl; //cout<<compress(d)<<endl; bfs(); //cout<<check(); //for(int i=1;i<=3;i++){for(int j=1;j<=3;j++)cout<<b[i][j]<<' ';puts("");} put(ans); return 0; }