Word:
/**
* 令字符串s为s[0],字符串t为s[n+1],其他字符串为s[1-n],每个字符串都对应一个编号
* 双重for循环遍历所有字符串对,若满足转换条件,则对应的编号连接一条权值为1的边,
* 显然满足转换条件当且仅当两个字符串有且仅有一个字符不同.
*
* 显然从s[0]到s[n+1]的最小操作数可以转换为从点0到点n+1的最短路径长度
*
* 因此连完边之后直接跑最短路算法,由于边权都为1,故可直接使用bfs跑最短路,
* 同时用last数组记录路径,
* last[i]表示从s[last[i]]转换到s[i]是从s[0]到s[i]最短路上的最后一步.
* 详见代码.
*/
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using std::cin;
using std::cout;
const int maxn=2e3+5;
const int maxm=4e6+5;
int head[maxn],to[maxm],ne[maxm],id;
void add(int x,int y){
ne[++id]=head[x],head[x]=id,to[id]=y;
ne[++id]=head[y],head[y]=id,to[id]=x;
}
int n,m;
std::string s[maxn];
bool canAddEdge(int i,int j){
int cnt=0;
for(int k=0;k<m;k++){
cnt+=s[i][k]!=s[j][k];
}
return cnt==1;
}
int d[maxn];//从0到i的最短路径
int last[maxn];//从0到i的最短路径上,最后一个是从last[i]到达i
bool vis[maxn];//从0是否可以到达i
void bfs(){
std::queue<int> que;
que.push(0);
vis[0]=true,d[0]=0,last[0]=-1;
while(!que.empty()){
int i=que.front();
que.pop();
for(int e=head[i],id=to[e];e;e=ne[e],id=to[e]){
//id之前已经可以被其他点遍历了,
//根据bfs的特性,此处再次到达的路径和先前的路径长度相等或者更大,不优,因此直接continue
if(vis[id])continue;
//id先前还没遍历过,此处是第一次遍历到,必定是最短的距离
que.push(id);
//更新对应的数组值
d[id]=d[i]+1,last[id]=i,vis[id]=true;
}
}
}
void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>s[i];
cin>>s[0]>>s[n+1];
for(int i=0;i<=n+1;i++){
for(int j=i+1;j<=n+1;j++){
if(canAddEdge(i,j)){
add(i,j);
}
}
}
//特判掉s==t的情况
if(s[0]==s[n+1]){
cout<<0<<endl;
cout<<s[0]<<endl;
cout<<s[n+1]<<endl;
return;
}
bfs();
if(!vis[n+1]){
cout<<-1<<endl;
return;
}
int now=n+1;
std::vector<int> path;
while(now!=-1){
path.push_back(now);
now=last[now];
}
cout<<d[n+1]-1<<endl;
for(auto it=path.rbegin();it!=path.rend();it++){
cout<<s[*it]<<endl;
}
}
signed main(){
// freopen("file.txt","r",stdin);
// std::ios_base::sync_with_stdio(false);
// std::cin.tie(nullptr),std::cout.tie(nullptr);
// cout<<std::fixed<<std::setprecision(15);
int tt=1;//cin>>tt;
while(tt--)solve();
return 0;
}
啊宁去游玩
/**
* 思维+dijkstra模板
* 假设从1号点到达点x的最短距离为d[x],此时到达点u(d[u]已知),邻点为v(d[v]未知),
* 则在最小花费的情况下, 此时"u和v的属性关系一定和初始关系一样",
* 因为从1->u的最短路径路径必然没有经过v(如果经过v, 则d[v]已知),
* 因此从1->u的最短路径中,无论使用多少次膜法,
* u和v的属性都会同时改变所以当恰好到达u点时,故u和v的属性关系一定和初始关系一样.
*
*
* 初始关系一样则意味这从u->v的花费是确定
* 所以从u->v有两种选择:使用与不使用膜法
* 根据u和v的属性关系,又可分两种情况:
* 若u和v初始属性相同,则u->v的花费为min(x,z+y);
* 否则u->v的花费为min(z+x,y)
*
* 由于d[1]=0(已知),而d[2-n]未知
* 因此直接建图从1号点开始递推,跑堆优化的dijkstra即可
*/
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using std::cin;
using std::cout;
const int maxn=2e5+5;
const int maxm=4e5+5;
int n,m,x,y,z;
bool a[maxn];
int head[maxn],to[maxm],ne[maxm],w[maxm],id;
void add(int x,int y,int z){
ne[++id]=head[x],head[x]=id,to[id]=y,w[id]=z;
ne[++id]=head[y],head[y]=id,to[id]=x,w[id]=z;
}
#define fi first
#define se second
#define pii std::pair<int,int>
int d[maxn];
bool vis[maxn];
int dijkstra(){
for(int i=2;i<=n;i++)d[i]=1e18;
std::priority_queue<pii,std::vector<pii>,std::greater<pii>> que;
que.push({0,1});
while(!que.empty()){
int i=que.top().se,cost1=que.top().fi;
que.pop();
if(vis[i])continue;
vis[i]=true;
for(int e=head[i],id=to[e];e;e=ne[e],id=to[e]){
if(vis[id])continue;
int cost2=cost1+w[e];
if(d[id]>cost2){
d[id]=cost2;
que.push({d[id],id});
}
}
}
return d[n];
}
void solve(){
cin>>n>>m;
cin>>x>>y>>z;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
add(u,v,(a[u]==a[v]?std::min(x,y+z):std::min(y,x+z)));
}
cout<<dijkstra()<<endl;
}
signed main(){
// freopen("file.txt","r",stdin);
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr),std::cout.tie(nullptr);
// cout<<std::fixed<<std::setprecision(15);
int tt=1;//cin>>tt;
while(tt--)solve();
return 0;
}