Hide and Seek 捉迷藏
Description
贝茜在和约翰玩一个“捉迷藏”的游戏.
她正要找出所有适合她躲藏的安全牛棚.一共有N(2≤N≤20000)个牛棚,被编为1到N号.
她知道约翰(捉牛者)从牛棚1出发.所有的牛棚由M(1≤M≤50000)条双向路连接,每条双向路连接两个不同的牛棚.
所有的牛棚都是相通的.贝茜认为同牛棚1距离最远的的牛棚是安全的.
两个牛棚间的距离是指,从一个牛棚到另一个牛棚最少需要通过的道路数量.请帮贝茜找出所有的安全牛棚.
Format
Input
第1行输入两个整数N和M,
之后M行每行输入两个整数,表示一条路的两个端点
Output
仅一行,输出三个整数.第1个表示安全牛棚(如果有多个,输出编号最小的);第2个表示牛棚1和安全牛棚的距离;第3个表示有多少个安全的牛棚
Samples
输入数据 1
6 7
3 6
4 3
3 2
1 3
1 2
2 4
5 2
输出数据 1
4 2 3
单元最短路——dijkstra板子
dijkstra算法的精髓在于每个队列头都是对于当前点的最优解,进而以当前点为中转点,更新与其直接相连的点。
#include<bits/stdc++.h>
using namespace std;
int n,m,mx,ans,d[20003],to;
bool vis[20003],fg=false;
vector<int>f[20003];
struct node
{
int u,dist;
};
bool operator<(node a,node b)
{
return a.dist>b.dist;
}
priority_queue<node> q;
node temp;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&mx,&ans);
f[mx].push_back(ans);
f[ans].push_back(mx);
}
memset(vis,false,sizeof(vis));
memset(d,127/2,sizeof(d));
d[1]=0;
q.push({1,0});
while(q.empty()==false)
{
temp=q.top();
q.pop();
if(vis[temp.u]==true)
continue;
vis[temp.u]=true;
for(int i=0;i<f[temp.u].size();i++)
{
to=f[temp.u][i];
if(d[to]>d[temp.u]+1)
{
d[to]=d[temp.u]+1;
q.push({to,d[to]});
}
}
}
mx=0;
ans=0;
for(int i=1;i<=n;i++)
mx=max(mx,d[i]);
for(int i=1;i<=n;i++)
if(d[i]==mx)
{
if(fg==false)
{
fg=true;
printf("%d ",i);
}
ans++;
}
printf("%d %d",mx,ans);
return 0;
}
[JLOI2011]飞行路线
Description
Alice 和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这 些城市分别标记为0到n-1,一共有m种航线,每 种航线连接两个城市,并且航线有一定的价格。
Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推 出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?
Input
数据的第一行有三个整数,n,m,k,分别表示城市数,航线数和免费乘坐次数。
第二行有两个整数,s,t,分别表示他们出行的起点城市编号和终点城市编号。(0<=s,t<n)
接下来有m行,每行三个整数,a,b,c,表示存在一种航线,能从城市a到达城市b,或从城市b到达城市a,价格为c。
(0<=a,b<n,a与b不相等,0<=c<=1000) 2<=n<=10000,1<=m<=50000,0<=k<=10.
Output
只有一行,包含一个整数,为最少花费。
Samples
输入数据 1
5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100
输出数据 1
8
最短路+dp
dp的状态为使用免费的次数
#include<bits/stdc++.h>
using namespace std;
int n,m,k,s,t,x,y,z,u,v,fr,to;
bool vis[10003][12];
struct node
{
int u,v,fr;
};
vector<node>mp[10003];
priority_queue<node> q;
bool operator<(node a,node b)
{
return a.v>b.v;
}
node temp;
int main()
{
scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
mp[x].push_back({y,z,0});
mp[y].push_back({x,z,0});
}
memset(vis,false,sizeof(vis));
q.push({s,0,0});
while(q.empty()!=true)
{
temp=q.top();
q.pop();
u=temp.u;
v=temp.v;
fr=temp.fr;
if(u==t)
{
printf("%d",v);
return 0;
}
if(vis[u][fr]==true)
continue;
vis[u][fr]=true;
for(int i=0;i<mp[u].size();i++)
{
to=mp[u][i].u;
if(fr<k)
q.push({to,v,fr+1});
q.push({to,v+mp[u][i].v,fr});
}
}
return 0;
}
最小生成树板子
传送门P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<bits/stdc++.h>
using namespace std;
long long n,m,x,y,z,ans[5002],p,vp,ex,now,to;
bool vis[5002],fg;
struct node
{
long long u,v;
};
vector<node>f[5002];//f[i][j].u-节点i的第j个连接点的编号 f[i][j].v-节点i的第j个连接点的权值
node temp;
bool operator<(node a,node b)
{
return a.v>b.v;
}
priority_queue<node> q;
int main()
{
scanf("%lld%lld",&n,&m);
memset(vis,false,sizeof(vis));//是否在树内
vis[1]=true;//节点1已经加入树
ans[1]=1;//以1为树内第一个点
for(int i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&x,&y,&z);
f[x].push_back({y,z});
f[y].push_back({x,z});
}
for(int i=2;i<=n;i++)
{
now=ans[i-1];//当前点
for(int j=0;j<f[now].size();j++)
q.push({f[now][j].u,f[now][j].v});//加入与当前点相连的点
fg=false;//还没有找到下一个点(要求是不在树内且连入代价最低)
while(fg==false)
{
if(q.empty()==true)//无解
{
printf("orz");
return 0;
}
temp=q.top();
q.pop();
if(vis[temp.u]==false)//与树中点相连的点不在树内,符合条件加入树
{
fg=true;
ex+=temp.v;
ans[i]=temp.u;
vis[temp.u]=true;
}
}
}
printf("%lld",ex);
return 0;
}