B - Bumped!
题意:
给定n个点m条边组成的无向图,给定起点和终点,其中会提供机票使有的线路直接到达无需花费(单程且只能选择一次),求从起点到终点的最短路。
题目分析:
首先明确机票可以选择也可以不选择,可以先跑一遍dijkstra找出最短距离,然后加入机票航线并不断更新最小值,且每次更新完需要删除新加入的机票航线,当时删除边的操作脑子有点乱,当时数组模拟邻接表有点遗忘h数组的含义
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=1e9+7;
const int N=1e6+10;
int dis[N];
bool st[N];
int h[N],e[N],ne[N],idx,w[N];
int n,m,q,start,ed;
void add(int a,int b,int c)
{
w[idx]=c;
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
int dij(int start,int ed)
{
memset(dis,0x3f,sizeof(h));
memset(st,0,sizeof(st));
dis[start]=0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,start});
while(heap.size()){
auto t=heap.top();
heap.pop();
int u=t.se;
if(st[u]) continue;
st[u]=true;
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(dis[j]>dis[u]+w[i]){
dis[j]=dis[u]+w[i];
heap.push({dis[j],j});
}
}
}
return dis[ed];
}
signed main()
{
fast;
cin>>n>>m>>q>>start>>ed;
memset(h,-1,sizeof(h));
while(m--){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
int minv=dij(start,ed);
while(q--){
int a,b;
cin>>a>>b;
int x=h[a];
add(a,b,0);
minv=min(minv,dij(start,ed));
h[a]=x;
}
cout<<minv<<endl;
return 0;
}
C - Canonical Coin Systems
题意:
求给定的货币系统贪心凑钱是不是最优策略
题目分析:
n的范围很小,分别求出完全背包和贪心组成所有钱的方案数,然后逐个比较,输出答案即可。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=1e9+7;
const int N=2e6+10;
int w[N],n;
int dp[N];
int getmax[N];
signed main()
{
fast;
cin>>n;
for(int i=1;i<=n;i++) cin>>w[i];
memset(dp,0x3f,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=N;j++)
if(j>=w[i])
dp[j]=min(dp[j],dp[j-w[i]]+1);
for(int i=0;i<=N;i++)
for(int j=1;j<=n;j++)
if(i>=w[j])
getmax[i]=getmax[i-w[j]]+1;
bool flag=true;
for(int i=0;i<N;i++)
if(getmax[i]!=dp[i]){
flag=false;
break;
}
if(flag) cout<<"canonical"<<endl;
else cout<<"non-canonical"<<endl;
return 0;
}
F - GlitchBot
题意:
给定n条指令,其中一条发生错误无法从起点到达终点,起点坐标起始方向固定,求出错误指定。
题目分析:
暴力枚举所有指令,然后每次替换掉指令,根据指令模拟走一遍,如果可以到达终点输出答案,细节方面注意下方向的定义顺序,每次记得恢复现场。
果然暴力也是需要技巧的,自己写的思路很混乱。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=1e9+7;
const int N=2e6+10;
string step[60];
int x,y,n;
string t[]={"Forward","Right","Left"};
bool judge(string step[])
{
int sx=0,sy=0,turn=1;//方向定义顺序为右上左下,方向初始向上turn初始为1
for(int i=0;i<n;i++){
if(step[i]=="Forward"){
sx+=dx[turn];
sy+=dy[turn];
}
else if(step[i]=="Right"){
turn--;
if(turn<0) turn=3;
}
else if(step[i]=="Left"){
turn++;
if(turn>3) turn=0;
}
}
if(sx==x&&sy==y) return true;
else return false;
}
signed main()
{
cin>>x>>y>>n;
for(int i=0;i<n;i++) cin>>step[i];
for(int i=0;i<n;i++){
string p=step[i];
for(int j=0;j<3;j++){
step[i]=t[j];
if(judge(step)){
cout<<i+1<<' '<<step[i]<<endl;
return 0;
}
step[i]=p;//复原
}
}
return 0;
}
G - Greeting Card
题意:
求n个点中距离为2018坐标对的数量
题目分析:
其实给定的样例就能提醒我们打表看看规律,不难发现距离2018的点,满足:①x距离差2018,y相等 ②x相等,y差2018 ③x差1680,y差1118 ④x差1118,y差1680,我们存下来这12种情况,然后遍历每个点的12个方向,如果存在这个点,答案加一。
其中用map+pair记录出现次数。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=1e9+7;
const int N=1e6+10;
map<PII,int>mp;
int n;
int sum;
int dir[12][2]={{2018,0},{-2018,0},{0,2018},{0,-2018},{1118,1680},{-1118,1680},{1118,-1680},{-1118,-1680},{1680,1118},{-1680,1118},{1680,-1118},{-1680,-1118}};
signed main()
{
cin>>n;
while(n--){
int x,y;
cin>>x>>y;
sum+=mp[{x,y}];
for(int i=0;i<12;i++)
mp[{x+dir[i][0],y+dir[i][1]}]++;
}
cout<<sum<<endl;
return 0;
}