武科训练赛题解
1.
求一个数的k的倍数数位和的最小值。这个题目的关键是数位和,数的本身并不关心。所以只需要求每个数位上的和就好。很明显每一个数他的每一位都是可以通过乘10和加+1操作形成的。但是加一是很方便的,乘上一个10是很不容易操作的。所以我们考虑用01bfs。01bfs有什么好处呢,当乘上10的时候我只需要再末尾加上一个0就好了(也就是乘以10)。由于10肯定优于操作+1,所以优先考虑10。这个时候考虑用deque,更优解放在头部。还有就是这么k的倍数可以是无穷,如何处理这个问题呢?我们只需要考虑取模k后的值,因为当这个值等于0时就是解。
2.
考虑让每个棋子才踩在自己的点上才算结束,我考虑以这种情况作为结束1234567890,然后bfs搜索,每次将坐标上没有棋子的那个点与他有边相连的点交换。然后继续bfs
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define fel(i,x,y) for(int i=x;i<=y;i++)
#define fhl(i,x,y) for(int i=x;i>=y;i--)
#define inf 0x3fffffff
#define ll long long
#define pb push_back
#define endl "\n"
//就是每次bfs看有没有点可以踩到自己对点上,如果有那就不再动他。
//主要是还存在一个问题,我考虑先让那个点动呢?
//我觉得应该先知道每个点距离他的终点的最近距离,然后先搜这个点。这个感觉可以用dfs搜一下int m,x,y,ans;
//还是没想到
//最后解法就是将每个点带到自己点上,也就是这种情况123456780
//然后每次对那个空的点进行搜索,看哪些点可以到这个位置上。
#define int long long
typedef pair<int,int>PII;
const int N=20;
int m,x,y,ans,t;
int a[N];
vector<int>b[N];
map<int,int>vis;
void bfs(){
queue<PII>q;
t=0;
for(int i=1;i<=9;i++){
t=t*10+a[i];
}
//cout<<t<<endl;
vis[t]=1;
q.push({t,0});
while(!q.empty()){
auto [now,step]=q.front();
if(now==123456780){
cout<<step;
return;
}
//cout<<now<<endl;
q.pop();
for(int i=9;i>=1;i--){
a[i]=now%10;
now/=10;
}
for(int i=1;i<=9;i++){
if(a[i]>0) continue;
for(auto j:b[i]){
swap(a[j],a[i]);
t=0;
for(int k=1;k<=9;k++){
t=t*10+a[k];
}
if(!vis[t]){
q.push({t,step+1});
vis[t]=1;
}
swap(a[j],a[i]);
}
}
}
cout<<-1<<endl;
}
signed main(){
cin>>m;
fel(i,1,m){
cin>>x>>y;
b[x].pb(y);
b[y].pb(x);
}
for(int i=1;i<=8;i++){
cin>>t;
a[t]=i;
}
bfs();
return 0;
}
3.
拓扑排序。然后需要考虑尽量字典序大,考虑用一个优先队列,建成小顶堆就可以了。这样就可以保证都可以输出的情况下先输出小的。
