文章目录
A.Coloring Contention
思路:最短路减1
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
const int INF=99999999;
const int N=1000100;
const int M=1000100;
int h[N], e[M], w[M], ne[M], idx;
int dist[N], st[N];//表示该是否已经确定
//h头节点 e表边 w表示边权值 ne 表示下一条与起点连接的边的编号 idx 表示边的数量以及最新插入的边的编号
typedef pair<int, int> PII;
//记录节点的编号以及到节点的距离
void add(int a, int b, int c) // 添加一条边a->b,边权为c
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
void dijkstra() // 求1号点到n号点的最短路距离
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
//优先队列
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 1});
while (heap.size())
{
PII t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if (st[ver]) continue;
st[ver] = true;
for (int i = h[ver]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
heap.push({dist[j], j});
}
}
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h));
int i,j,k,x,y,v;
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y,1);
add(y,x,1);
}
dijkstra();
printf("%d\n",dist[n]-1);
}
B.Jzzhu and Cities *
传送门
思路:跑个最短路,然后判断。我那个判断没写好,就wa了,之后会补
C.Find them, Catch them
传送门
题目大意:给你A是查询两个的关系,D是说明那两个在不同阵营
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxx=100050;
int f[maxx],deep[maxx];
void init()
{
for(int i=1;i<=maxx;i++)
{
f[i]=i;
}
}
int find(int x)
{
if(f[x]==x) return x;
int t=f[x];
f[x]=find(f[x]);
deep[x]=(deep[x]+deep[t])%2;
return f[x];
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int m,n,i;
scanf("%d%d",&n,&m);
getchar();
char a;int x,y;
init();
memset(deep,0,sizeof(deep));
for(i=0;i<m;i++)
{
scanf("%c %d %d",&a,&x,&y);
getchar();
int s1,s2;
s1=find (x),s2=find(y);
if(a=='A')
{
if(s1==s2)
{if(deep[x]==deep[y])
printf("In the same gang.\n");
else printf("In different gangs.\n");
}
else printf("Not sure yet.\n");
}
else { f[s1]=s2;
deep[s1]=(deep[y]+1-deep[x])%2;
}
}
}return 0;
}
D.Cube Stacking
传送门
题目大意:有若干个方块,经p次操作后,在x方块下面的方块有多少个。
M操作—>将包含x方块的堆移到含y方块的堆上
C操作—>输出x方块下方方块的数目
解题思路:以堆最底部的方块作为父节点,dis[a]表示a到父节点的距离,rank[y]表示以y为底部的方块堆的大小,即含有多少个方块,借用find()更新dis。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int Max=30005;
int x,y;
char a;
int dis[Max],f[Max],length[Max];//length到底的距离,f到上一级的距离
int find(int x)
{
if(x==f[x])return x;
int fx=find(f[x]);
dis[x]+=dis[f[x]];
return f[x]=fx;
}
void merege(int x, int y) {
int fx = find(x), fy = find(y);
if (fx == fy) return ;
//将一堆的根节点作为另一堆根节点的上级
f[fx] = fy;
//更新作为子结点的根节点到其父节点的距离 同时更新合并后两堆的总数
dis[fx] += length[fy], length[fy] += length[fx];
}
int main()
{
int i,t;
scanf("%d",&t);
for(i=1;i<=Max;i++)
f[i]=i,length[i]=1;
while(t--)
{ getchar();
scanf("%c",&a);
if(a=='M')
{
scanf("%d%d",&x,&y);
merege(y,x);
}
else if(a=='C') {scanf("%d",&x);
printf("%d\n",length[find(x)]-dis[x]-1);
}
}
}
E.胜利大逃亡(续) *
F.Don’t Get Rooked
传送门
题目大意:没有相隔的墙,两个球不能放到同一行和列,问最多能放多少
#include<iostream>
#include<cstring>
#include<math.h>
#include<algorithm>
using namespace std;
char Map[5][5];
int mp[5][5];
int sum,n,sun;
int mov[][2]={0,1,0,-1,1,0,-1,0};
int mak(int x,int y)
{ int i;
if(mp[x][y]||Map[x][y]=='X')
return 0;
for(i=x-1;i>=0;i--)
{
if(Map[i][y]=='X')
break;
if(mp[i][y])
return 0;
}
for(i=x+1;i<n;i++)
{ if(Map[i][y]=='X')
break;
if(mp[i][y])
return 0;
}
for(i=y-1;i>=0;i--)
{if(Map[x][i]=='X')
break;
if(mp[x][i])
return 0;
}
for(i=y+1;i<n;i++)
{if(Map[x][i]=='X')
break;
if(mp[x][i])
return 0;
}return 1;
}
void dfs(int num)
{ sum=(sum>num?sum:num);
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(mak(i,j))
{
mp[i][j]=1;
dfs(num+1);
mp[i][j]=0;
}
}
int main()
{
while(1)
{ scanf("%d",&n);
getchar();
if(n==0)
break;
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
cin>>Map[i][j];
sum=0;
memset(mp,0,sizeof(mp));
dfs(0);
cout<<sum<<endl;
}
}
G. Igor In the Museum
传送门
题目大意:就是输入坐标可移动,问最多能看到多少画
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char Map[1001][1001];
int Mapv[1001][1001];
int sun[1000001];
int mov[][2]={0,1,0,-1,1,0,-1,0};
int sum;
int n,m,k,p;
void dis(int x,int y)
{ int x1,y1;
int i,j;
Mapv[x][y]=sum;;
for(i=0;i<4;i++)
{
x1=x+mov[i][0];
y1=y+mov[i][1];
if(Map[x1][y1]=='*')
sun[sum]++;
if(x1>0&&x1<=n&&y1>0&&y1<=m&&Mapv[x1][y1]==0)
{
if(Map[x1][y1]=='.')
dis(x1,y1);
}
}
}
int main()
{
int i,j;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;i++)
{getchar();
for(j=1;j<=m;j++)
{
scanf("%c",&Map[i][j]);
}
}
int x,y,t;
for(t=0;t<k;t++)
{ scanf("%d%d",&x,&y);
if(Mapv[x][y]!=0)
printf("%d\n",sun[Mapv[x][y]]);
else {sum++;dis(x,y);
printf("%d\n",sun[sum]);
}
}
return 0;
}
H.Eight
传送门
题目大意:将期恢复为12345678X最少需要几步
思路:用一个曼哈顿数
#include<iostream>
#include<queue>
#include<vector>
#include<map>
#include<cmath>
#include<algorithm>
using namespace std;
typedef pair<int,string> PIS;
//定义小跟堆
priority_queue<PIS,vector<PIS>,greater<PIS> > q;
string anss = "12345678x";//目标状态
//求曼哈顿距离的函数
int f(string s){
int res = 0;
for(int i = 0;i<9;i++){
if(s[i] == 'x') continue;
int a = s[i]-'1';
res += abs(i/3-a/3)+abs(a%3-i%3);
}
return res;
}
//当前状态的具体步数
map<string,string> ma;
string bfs(string s){
int i;
//优先队列存入期望步数+实际步数,和具体方案
q.push({f(s)+0,s});
ma[s] = "";//第一次放入队列为空
int xx[] = {-1,1,0,0};//表示上下左右,udlr
int yy[] = {0,0,-1,1};
string dir = "udlr";
while(!q.empty()){
PIS t = q.top();
q.pop();
string s = t.second;
if(s == anss) return ma[s];
//算出x的位置
int x,y;
for(i = 0;i<=9;i++)
if(s[i] == 'x'){
x = i/3;y= i%3;
}
for(int i = 0;i<4;i++){
int x1 = x+xx[i],y1 = y+yy[i];
if(x1<0 || x1>2 || y1<0 || y1>2) continue;
string s1 = s;//赋值数组
swap(s1[x1*3+y1],s1[x*3+y]);
int dis = ma[s].length()+1;
//如果访问过,并且比当前距离还小,continue;
if(ma.count(s1) == 1 && dis>=ma[s1].size()) continue;
ma[s1] = ma[s]+dir[i];
//进队
q.push({dis + f(s1),s1});
}
}
return " ";
}
int main(){
int i,j;
string a;
string s;//初始状态
for(i = 1;i<=9;i++){
cin>>a;
s+=a;
}
//先求逆序对的数量,逆序对的数量为奇数则无解
int cnt = 0;
for(i =0;i<8;i++){
for(j = i+1;j<9;j++){
if(s[i] == 'x' || s[j] == 'x') continue;
if(s[i]>s[j]){
cnt++;
}
}
}
if(cnt%2 == 1)
cout<<"unsolvable";
else{
cout<<bfs(s);
}
return 0;
}
I.Remmarguts’ Date *
J.Nightmare Ⅱ
传送门
思路:双向dfs
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char Map[1001][1001];
int Mapv[1001][1001];
int sun[1000001];
int mov[][2]={0,1,0,-1,1,0,-1,0};
int sum;
int n,m,k,p;
void dis(int x,int y)
{ int x1,y1;
int i,j;
Mapv[x][y]=sum;;
for(i=0;i<4;i++)
{
x1=x+mov[i][0];
y1=y+mov[i][1];
if(Map[x1][y1]=='*')
sun[sum]++;
if(x1>0&&x1<=n&&y1>0&&y1<=m&&Mapv[x1][y1]==0)
{
if(Map[x1][y1]=='.')
dis(x1,y1);
}
}
}
int main()
{
int i,j;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;i++)
{getchar();
for(j=1;j<=m;j++)
{
scanf("%c",&Map[i][j]);
}
}
int x,y,t;
for(t=0;t<k;t++)
{ scanf("%d%d",&x,&y);
if(Mapv[x][y]!=0)
printf("%d\n",sun[Mapv[x][y]]);
else {sum++;dis(x,y);
printf("%d\n",sun[sum]);
}
}
return 0;
}