Emergency
思路:
Dijkstra+更新各种信息
代码:
#include <bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=505;
int g[N][N],vis[N],w2[N],d[N];
int w[N],num[N];
int n,m,st,en;
void dij(){
memset(d,0x3f,sizeof d);
d[st]=0;
num[st]=1;
w[st]=w2[st];//必须设
f(i,0,n){
int t=-1;
f(j,0,n)
if(!vis[j]&&(t==-1||d[t]>d[j]))t=j;
vis[t]=1;
f(j,0,n){
if(d[j]>d[t]+g[t][j]){
d[j]=d[t]+g[t][j];
num[j]=num[t];
w[j]=w2[j]+w[t];
}
else if(d[j]==d[t]+g[t][j]){
num[j]+=num[t];
//注意救援队数量越多越好,用"<"
if(w[j]<w2[j]+w[t]){
w[j]=w2[j]+w[t];
}
}
}
}
}
int main(){
cin>>n>>m>>st>>en;
f(i,0,n)cin>>w2[i];
memset(g,0x3f,sizeof g);
f(i,0,m){
int a,b,c;
cin>>a>>b>>c;
g[a][b]=g[b][a]=min(g[a][b],c);
}
dij();
cout<<num[en]<<" "<<w[en]<<endl;
}
类似的题目:
代码:
#include <bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=505;
int g[N][N],vis[N],w2[N],d[N];
int w[N],num[N],pre[N];
int n,m,st,en;
void pri(int t){
if(t==st){
cout<<t<<" ";
return;
}
else {
pri(pre[t]);
if(t!=en)cout<<t<<" ";
else cout<<t;
}
}
void dij(){
memset(d,0x3f,sizeof d);
d[st]=0;
num[st]=1;
w[st]=w2[st];//必须设
f(i,0,n){
int t=-1;
f(j,0,n)
if(!vis[j]&&(t==-1||d[t]>d[j]))t=j;
vis[t]=1;
f(j,0,n){
if(d[j]>d[t]+g[t][j]){
d[j]=d[t]+g[t][j];
num[j]=num[t];
w[j]=w2[j]+w[t];
pre[j]=t;
}
else if(d[j]==d[t]+g[t][j]){
num[j]+=num[t];
//注意救援队数量越多越好,用"<"
if(w[j]<w2[j]+w[t]){
w[j]=w2[j]+w[t];
pre[j]=t;
}
}
}
}
}
int main(){
//freopen("E:\\信竞\\信竞文件夹\\in_c.TXT","r",stdin);
cin>>n>>m>>st>>en;
f(i,0,n)cin>>w2[i];
memset(g,0x3f,sizeof g);
f(i,0,m){
int a,b,c;
cin>>a>>b>>c;
g[a][b]=g[b][a]=min(g[a][b],c);
}
dij();
cout<<num[en]<<" "<<w[en]<<endl;
pri(en);
}
Travel Plan
思路:
和上一题差不多 , Dijkstra+更新各种信息
代码:
#include<bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=505;
int d[N],c[N],vis[N],pre[N];
int g1[N][N],g2[N][N];
int n,m,st,en;
void pri(int t){
if(t==st){
cout<<t<<" ";
return ;
}
else{
pri(pre[t]);
cout<<t<<" ";
}
}
void dij(){
memset(d,0x3f,sizeof d);
memset(c,0,sizeof c);
d[st]=0;
c[st]=0;
f(i,0,n){
int t=-1;
f(j,0,n)
if(!vis[j]&&(t==-1||d[t]>d[j]))t=j;
vis[t]=1;
f(j,0,n){
if(d[j]>d[t]+g1[t][j]){
d[j]=d[t]+g1[t][j];
c[j]=c[t]+g2[t][j];
pre[j]=t;
}
else if((d[j]==d[t]+g1[t][j]) && c[j]>c[t]+g2[t][j]){
c[j]=c[t]+g2[t][j];
pre[j]=t;
}
}
}
}
int main(){
// freopen("E:\\信竞\\信竞文件夹\\in_c.TXT","r",stdin);
cin>>n>>m>>st>>en;
memset(g1,0x3f,sizeof g1);
memset(g2,0x3f,sizeof g2);
f(i,0,m){
int a,b,c,d;
cin>>a>>b>>c>>d;
g1[a][b]=g1[b][a]=min(g1[a][b],c);//dis
g2[a][b]=g2[b][a]=min(g2[a][b],d);//cost
}
dij();
pri(en);
cout<<d[en]<<" "<<c[en];
}
Gas Station
题意:
从m个加油站里面选取1个站点,让他离居民区的最近的人最远,并且没有超出服务范围dist之内。
如果有很多个最远的加油站,输出距离所有居民区距离平均值最小的那个,如果平均值还是一样,就输出按照顺序排列加油站编号最小的那个
思路:
对n+m个点进行Dijkstra计算最短路径,记录相关信息即可
代码:
#include<bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=1e3+20;
const int inf=0x3f3f3f3f;
int n,m,k,ds;
int g[N][N],vis[N],d[N];
void dij(int p){
memset(d,0x3f,sizeof d);
memset(vis,0,sizeof vis);
d[p]=0;
f(i,0,n+m){
int t=-1;
//要对所有的点进行最短路(不止1~n)
ff(j,1,n+m)
if(!vis[j] && (t==-1||d[t]>d[j])) t=j;
vis[t]=1;
ff(j,1,n+m)
d[j]=min(d[j],d[t]+g[t][j]);
}
}
int f1(string s){
int l=s.length();
int t=0;
if(s[0]=='G'){
f(i, 1, l)
t=t*10+(s[i]-'0');
t+=n;//
}
else{
f(i, 0, l)
t=t*10+(s[i]-'0');
}
return t;
}
int main(){
freopen("E:\\信竞\\信竞文件夹\\in_c.TXT","r",stdin);
cin>>n>>m>>k>>ds;
memset(g,0x3f,sizeof g);
//防止有自环
f(i,1,N)g[i][i]=0;
f(i,0,k){
string s1,s2;
int t;
cin>>s1>>s2>>t;
int t1=f1(s1),t2=f1(s2);
//防止有重边
g[t1][t2]=g[t2][t1]=min(g[t1][t2],t);
}
double ind=-1,mx=-inf,ave=inf;
ff(i,n+1,n+m){
double t_ave=0,t_mn=inf;
dij(i);
ff(j,1,n){
if(d[j]>ds){
t_mn=-1;
break;
}
//先找离居民区的最近的人
if(d[j] < t_mn)
t_mn=d[j];
t_ave+=1.0*d[j]/n;
}
if(t_mn == -1)continue;
if(t_mn > mx){
mx=t_mn, ind= i - n, ave=t_ave;
}
else if(t_mn == mx && t_ave < ave){
ind=i-n, ave=t_ave;
}
}
if(ind==-1)cout<<"No Solution"<<endl;
else printf("G%d\n%.1lf %.1lf", (int)ind, mx, ave);
}
也可以用substr
函数和stoi
函数函数来简单优化:
substr
函数用法(截取指定位置,长度的字符串):
代码:
string s="abcdef";
cout<<s.substr(0,2)<<endl;
cout<<s.substr(1,2)<<endl;
cout<<s.substr(2,2)<<endl;
cout<<s.substr(0)<<endl;
cout<<s.substr(1)<<endl;
cout<<s.substr(2)<<endl;
输出:
ab
bc
cd
abcdef
bcdef
cdef
stoi
函数用法(将
n
n
n 进制的字符串转化为10进制):
注意:蓝桥杯可能无法运行此类函数,不推荐在 OI 赛制的比赛里使用
代码:
//stoi(字符串,起始位置,n进制),将 n 进制的字符串转化为10进制
//将2进制的字符串 str 转换为10进制(从0位置开始,到其末尾)
string str = "1010";
int a = stoi(str, 0, 2);
cout << a << endl;
//默认是将字符串整体以10进制转换为10进制
str = "234";
cout << stoi(str) << endl;
输出:
10
234
代码:
{
string s1,s2;
int t,t1,t2;
cin>>s1>>s2>>t;
if(s1[0] == 'G') {
s1 = s1.substr(1);
t1 = n + stoi(s1);
}
else t1 = stoi(s1);
if (s2[0] == 'G') {
s2 = s2.substr(1);
t2 = n + stoi(s2);
}
else t2 = stoi(s2);
//防止有重边
g[t1][t2]=g[t2][t1]=min(g[t1][t2],t);
}
All Roads Lead to Rome
1087 All Roads Lead to Rome (30 分)
思路:
统计信息,别乱就好 (写吐了)
代码:
#include<iostream>
#include<string>
#include<map>
using namespace std;
const int INF = 1e9;
const int N = 220;
int n, m,weight[N],g[N][N],d[N],w[N];
int pre[N], pt[N], num[N];
bool vis[N] ;
string st;
map <string, int> cityToID;
map<int, string> idToCity;
bool findID(string a) {
if (cityToID.find(a) != cityToID.end()) return true;
return false;
}
void Dijkstra(int s) {
fill(d, d + N, INF);
fill(pt, pt + N, 0);
fill(w, w + N, 0);
fill(num, num + N, 0);
d[s] = 0;
w[s] = weight[s];
num[s] = 1;
for (int i = 0; i < n; ++i) {
int u = -1, mn = INF;
for (int j = 0; j < n; ++j) {
if (!vis[j] && d[j] < mn) {
u = j;
mn = d[j];
}
}
//找不到小于INF的d[u] 说明剩下的顶点和起点a不连通
if (u == -1)return;
vis[u] = true; //别忘了标记
//用u去更新其他点
for (int v = 0; v < n; ++v) {
if (!vis[v] && g[u][v] != INF) {
if (d[u] + g[u][v] < d[v]) {
//st->v 变为 st->u->v
d[v] = d[u] + g[u][v];//最小花费
w[v] = w[u] + weight[v];//从起点到v点的幸福值之和
num[v] = num[u];//最短路径条数
pt[v] = pt[u] + 1;//最短路径上顶点数
pre[v] = u;//前驱
}
else if (d[u] + g[u][v] == d[v]) {//最小花费相同
num[v] += num[u];//更新最短路径条数
if (w[u] + weight[v] > w[v]) {//看幸福值
w[v] = w[u] + weight[v];
pt[v] = pt[u] + 1;
pre[v] = u;
}
}
else if (w[u] + weight[v] == w[v]) {//幸福值同
double uAvg = 1.0 * (w[u] + weight[v]) / (pt[u] + 1);
double vAvg = 1.0 * w[v] / pt[v];
if (uAvg > vAvg) {//看平均幸福值
pt[v] = pt[u] + 1;
pre[v] = u;
}
}
}
}
}
}
void printPath(int v) {
if (v == 0) {
cout << idToCity[v];
return;
}
printPath(pre[v]);
cout << "->" << idToCity[v];
}
int main(void) {
cin >> n >> m >> st;
string t;
int id = 0,numT;
cityToID[st] = id++;
idToCity[id - 1] = st;
for (int i = 0; i < n - 1; ++i) {
cin >> t >> numT;
cityToID[t] = id++;
idToCity[id - 1] = t;
weight[id - 1] = numT;
}
string a, b;
int dis = 0;
fill(g[0], g[0] + N * N, INF);
for (int i = 0; i < m; ++i) {
cin >> a >> b >> dis;
int x=cityToID[a],y=cityToID[b];
g[x][y] = dis;
g[y][x] = dis;
}
Dijkstra(0);
int rom = cityToID["ROM"];
printf("%d %d %d %d\n", num[rom], d[rom], w[rom], w[rom] / pt[rom]);
printPath(rom);
return 0;
}
Public Bike Management
1018 Public Bike Management (30 分)
思路:
只有在所有路径都确定了之后才能区选择最小的need和最小的back,dfs就行
代码:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 510; //最大顶点数
const int INF = 1e9; //无穷大
//n为顶点数,m为边数,Cmax为最大容量.Sp为问题站点
//G为邻接矩阵,weight为点权,minReamin记录最少带回的数目
int n, m, Cmax, Sp, numPath = 0, g[N][N], weight[N],d[N];
int vis[N] ;
vector<int> pre[N]; //前驱
vector<int> t_Path, path; //临时路径及最优路径
int minNeed = INF, minRemain = INF;
void Dijkstra(int s) {
fill(d, d + N, INF);
d[s] = 0;
for (int i = 0; i <= n; ++i) {
int u = -1, MIN = INF;
for (int j = 0; j <= n; ++j) {
if (!vis[j] && d[j] < MIN) {
u = j;
MIN = d[j];
}
}
//找不到小于INF的d[u],说明剩下的顶点和起点s不连通.
if (u == -1) return;
vis[u] = true; //标记u为已访问
for (int v = 0; v <= n; ++v) {
//如果v未访问u能到达v
if (!vis[v] && g[u][v] != INF) {
if (d[u] + g[u][v] < d[v]) {
d[v] = d[u] + g[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if (d[u] + g[u][v] == d[v]) pre[v].push_back(u);
}
}
}
}
void DFS(int v) {
if (v == 0) {
t_Path.push_back(v);
//路径tempPath上需要携带的数目,需要带回的数目
int need = 0, remain = 0;
for (int i = t_Path.size() - 1; i >= 0; --i) {//必须要倒着枚举
int id = t_Path[i];//当前结点编号为id
if (weight[id] > 0) remain += weight[id];
else {
if (remain > abs(weight[id])) remain -= abs(weight[id]);
else { //当前有的不够补给
need += abs(weight[id])-remain;
remain = 0;
}
}
}
if (need < minNeed) { //比较一下,那个需要的自行车少.
minNeed = need; //优化minNeed
minRemain = remain; //优化minRemain
path = t_Path;
}
else if (need == minNeed && remain < minRemain) {
//需要的自行车相同的.reamin带会来的变少了.
minRemain = remain; //优化需要带回的自行车
path = t_Path;
}
t_Path.pop_back();
return;
}
t_Path.push_back(v);
for (int i = 0; i < pre[v].size(); ++i) DFS(pre[v][i]);
t_Path.pop_back();
}
int main(void) {
scanf("%d%d%d%d", &Cmax, &n, &Sp, &m);
int u, v;
fill(g[0], g[0] + N * N, INF);
for (int i = 1; i <= n; ++i) {
scanf("%d", &weight[i]);
weight[i] -= Cmax / 2;
}
for (int i = 0; i < m; ++i) {
scanf("%d%d", &u, &v);
scanf("%d", &g[u][v]);
g[v][u] = g[u][v];
}
Dijkstra(0);
DFS(Sp);
printf("%d ", minNeed);
for (int i = path.size() - 1; i >= 0; --i) {
printf("%d", path[i]);
if (i > 0) printf("->");
}
printf(" %d", minRemain);
return 0;
}
直捣黄龙
代码:
#include<bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cout<<#x<<" : "<<x<<endl;
using namespace std;
//
const int N=205;
int g[N][N],w[N],st[N];
int n,m,cnt,t_1,t_2;
string s_1,s_2;
map<string,int> mp;
map<int,string> mp2;
//时间,路径数目,经过点数,杀敌数目,前驱结点
int d[N],num[N],sum[N],kl[N],pre[N];
void pri(int t){
if(t!=t_1){
pri(pre[t]);
cout<<"->"<<mp2[t];
}
else cout<<mp2[t];
}
void dij(){
memset(d,0x3f,sizeof d);
d[t_1]=0,num[t_1]=1;//路径初始化为1
f(k,0,n){
int t=-1;
f(i,0,n){
if(!st[i] && (t==-1||d[t]>d[i]))t=i;
}
st[t]=1;
f(i,0,n){
if(d[i]>d[t]+g[t][i]){
d[i]=d[t]+g[t][i];
num[i]=num[t];
sum[i]=sum[t]+1;
kl[i]=kl[t]+w[i];
pre[i]=t;
}
else if(d[i]==d[t]+g[t][i]){
num[i]+=num[t];
if(sum[i]<sum[t]+1){
sum[i]=sum[t]+1;
kl[i]=kl[t]+w[i];
pre[i]=t;
}
else if(sum[i]==sum[t]+1 && kl[i]<kl[t]+w[i]){
kl[i]=kl[t]+w[i];
pre[i]=t;
}
}
}
}
}
int main(){
cin>>n>>m>>s_1>>s_2;
mp[s_1]=cnt;mp2[cnt]=s_1;cnt++;
f(i,0,n-1){
string s;int t;
cin>>s>>t;
mp[s]=cnt;mp2[cnt]=s;w[cnt]=t;cnt++;
}
memset(g,0x3f,sizeof g);
f(i,0,m){
string s1,s2;int t;
cin>>s1>>s2>>t;
int x=mp[s1],y=mp[s2];
g[x][y]=g[y][x]=min(g[x][y],t);
}
t_1=mp[s_1],t_2=mp[s_2];
dij();
pri(t_2);
cout<<endl;
cout<<num[t_2]<<" "<<d[t_2]<<" "<<kl[t_2]<<endl;
}