第k短路
原题链接
![这里是引用](https://img-blog.csdnimg.cn/fee5d60ecf80462c95a9af33fa9754e9.png)
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define int long long
#define inf 0x3f3f3f3f
#define fi first
#define se second
using namespace std;
const int N=1010,M=3e4+10 ;
typedef pair<int,pair<int,int>> pii;
typedef pair<int,int> PII;
int h[N],rh[N],e[M],ne[M],w[M],idx;
int n,m;
int S,k,T;
int dist[N],cnt[N];
bool st[N];
void add(int h[],int a,int b,int c){
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void dij(){
memset(dist,0x3f,sizeof dist);
dist[T]=0;
for(int i=0;i<n;i++){
int t=-1;
for(int j=1;j<=n;j++){
if(!st[j]&&(dist[t]>dist[j]||t==-1))
t=j;
}
st[t]=true;
for(int r=rh[t];~r;r=ne[r]){
int j=e[r];
if(dist[j]>dist[t]+w[r])
dist[j]=dist[t]+w[r];
}
}
}
int astar(){
priority_queue<pii,vector<pii>,greater<pii> > q;
q.push({dist[S],{0,S}});
while(q.size()){
auto t=q.top();
q.pop();
int distance=t.se.fi,ver=t.se.se;
cnt[ver]++;
if(cnt[T]==k) return distance;
for(int i=h[ver];~i;i=ne[i]){
int j=e[i];
if(cnt[j]<k){
q.push({dist[j]+distance+w[i],{distance+w[i],j}});
}
}
}
return -1;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
memset(h,-1,sizeof h);
memset(rh,-1,sizeof rh);
cin>>n>>m;
while(m--){
int a,b,c;
cin>>a>>b>>c;
add(h,a,b,c),add(rh,b,a,c);
}
cin>>S>>T>>k;
if(S==T) k++;
dij();
cout<<astar();
return 0;
}
debug
- 输入顺序出错,导致答案错误
- 没有输入a,b,c时,会出现sf错误
- dijkstra算法里面for循环,变量用了两个i。一个全局fo依次找集合S的n个点,里面两个for,找当前距离S集合距离最近的点,一个用此点更新距离。
- 第k短路用cnt记录当前使用的点次数。
总结
- A*算法,首先求出当前状态到终点的估计距离(一定比真实距离小或者相等),可以逆向思维,即终点到当前距离的最小值。
- 用当前真实距离和估计距离排序(priority_queue),取最小的点来继续扩展。和bfs差不多,就是找点进行扩展。
八数码
原题链接
![这里是引用](https://img-blog.csdnimg.cn/47a333b0246540ebb45738058b1c1014.png)
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define int long long
#define fi first
#define se second
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef pair<int, string>pii;
const int N = 1100;
string s;
string ed="12345678x";
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
char op[5]="urdl";
int f(string s){
int ans=0;
for(int i=0;i<9;i++){
if(s[i]!='x'){
auto t=s[i]-'1';
ans+=abs(i/3-t/3)+abs(i%3-t%3);
}
}
return ans;
}
string astar(string s){
priority_queue<pii,vector<pii>,greater<pii> > h;
map<string,pair<string,char>> prev;
map<string,int> dist;
h.push({f(s),s});
dist[s]=0;
while(h.size()){
auto t=h.top();
h.pop();
string state=t.se;
if(state==ed){
break;
}
int step=dist[state];
int x,y;
for(int i=0;i<state.size();i++){
if(state[i]=='x'){
x=i/3,y=i%3;
break;
}
}
string source=state;
for(int i=0;i<4;i++){
int a=x+dx[i],b=y+dy[i];
if(a<0||a>2||b<0||b>2) continue;
swap(state[x*3+y],state[a*3+b]);
if(dist.count(state)==0||dist[state]>step+1){
dist[state]=step+1;
prev[state]={source,op[i]};
h.push({dist[state]+f(state),state});
}
swap(state[x*3+y],state[a*3+b]);
}
}
string res;
while (ed != s)
{
res += prev[ed].second;
ed = prev[ed].first;
}
reverse(res.begin(), res.end());
return res;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
char ch;
string ls;
for(int i=0;i<9;i++){
cin>>ch;
if(ch!='x') ls+=ch;
s+=ch;
}
int cnt=0;
for(int i=0;i<8;i++)
for(int j=i+1;j<8;j++)
if(ls[i]>ls[j]) cnt++;
if(cnt&1) cout<<"unsolvable";
else cout<<astar(s);
return 0;
}
debug
- 函数返回类型是string时,但是没有任何返回会sf错误,无语,我也不知道怎么回事
- 就是错误出现得很烦,然后注意int变成long long类型了,必要时候可以强制转换成类型一样的
总结
- A*算法就是用当前距离加估计距离排序的,所以dist和估计距离f(s)都不能缺少。
利用最小点扩展 - swap函数的用法