Atcoder Beginner Contest 317

 A - Potions (atcoder.jp)

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=110;
int a[N];
int n,h,x;
void solve() {
    cin>>n>>h>>x;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        if(h+a[i]>=x){
            cout<<i<<endl;
            return;
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}

B - MissingNo. (atcoder.jp)

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
int n;
void solve() {
    cin>>n;
    set<int>s;
    int maxn=0;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        maxn=max(maxn,x);
        s.insert(x);
    }
    int y=*s.begin();
    for(int i=y;i<=maxn;i++){
        if(!s.count(i)){
            cout<<i<<endl;
            return;
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}

C - Remembering the Days (atcoder.jp)

一开始想的是最大生成树,但是了第三个样例后,知道这是不行的,因为不能有重复路径,树是可以走重复路径的

然后想到用dfs,对于每一个点进行dfs,然后对于找到的单向路径长度之和取max

错误代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=15;
int vis[N];
vector<PII>e[N];
int n,m;
int ans;
void dfs(int x,int d) {
    vis[x]=1;
    if(!e[x].size()) {
        ans = max(ans, d);
        return;
    } else {
        for(auto v:e[x]) {
            int ver=v.first,dist=v.second;
            if(!vis[ver]) {
                dfs(ver,d+dist);
            }
        }
    }
}
void solve() {
    cin>>n>>m;
    for(int i=1; i<=m; i++) {
        int a,b,c;
        cin>>a>>b>>c;
        e[a].push_back({b,c});
        e[b].push_back({a,c});
    }
    ans=0;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) vis[j]=0;
        dfs(i,0);
    }
    cout<<ans<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}

错误之处在于:

第一个错误在于给答案赋值的时候,一直没有赋值进去,因为e[x],size()不可能等于0

其实完全可以一直赋值的,因为是取max,一直赋值的话是完全没有问题的

或者在遍历子节点时看有没有标记过的节点

第二个错误在于dfs没有恢复现场,当对图进行dfs时,一定要恢复现场

对图进行dfs的板子是固定的,如下:

void dfs(int x){
    vis[x]=1;
    for(auto v:e[x]){
        if(!vis[v]) dfs(v);
    }
    vis[x]=0;
}

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=15;
int vis[N];
vector<PII>e[N];
int n,m;
int ans;
void dfs(int x,int d) {
    vis[x]=1;
        ans=max(ans,d);
        for(auto v:e[x]) {
            int ver=v.first,dist=v.second;
            if(!vis[ver]) {
                dfs(ver,d+dist);
            }
        }
    vis[x]=0;
}
void solve() {
    cin>>n>>m;
    for(int i=1; i<=m; i++) {
        int a,b,c;
        cin>>a>>b>>c;
        e[a].push_back({b,c});
        e[b].push_back({a,c});
    }
    ans=0;
    for(int i=1; i<=n; i++) {
        for(int j=1;j<=n;j++) vis[j]=0;
        dfs(i,0);
    }
    cout<<ans<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}

D - President (atcoder.jp)

一开始想贪心,每次贪席位最多的,但是后面想了想是不可能的,因为可能席位最多的那个,需要转移很多很多很多很多的票

如果一开始有贪心的思路,那么先不要急着写代码,先思考该贪心思路是否真的可行

错误代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<stack>
#define endl '\n'
#define int long long
using namespace std;
typedef long long ll;
const int N=110;
int n;
struct node{
    int x,y,z;
    int diff;
    bool operator<(const node &W)const{
        if(z==W.z) return diff<W.diff;
        return z>W.z;
    }
}q[N];
void solve() {
    cin>>n;
    int sum=0;
    for(int i=1;i<=n;i++) {
        cin>>q[i].x>>q[i].y>>q[i].z;
        if(q[i].y>q[i].x) q[i].diff=q[i].y-q[i].x;
        else q[i].diff=0;
        sum+=q[i].z;
    }
    sort(q+1,q+1+n);
    int res=0;
    int ans=0;
//    for(int i=1;i<=n;i++){
//        cout<<q[i].x<<' '<<q[i].y<<' '<<q[i].z<<endl;
//    }
    for(int i=1;i<=n;i++){
        res+=q[i].z;
        if(q[i].diff) ans+=q[i].diff/2+1;
        if(sum-res<res) break;
    }
    cout<<ans<<endl;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}

 

这题其实是01背包的变式,与经典的01背包问题不同,f[i][j]表示在前i个物品里选,价值为j所需要的物品最小重量

该题f[i][j]表示在前i场投票中选择若干场投票进行票数转移,赢得j个席位所需要转移的最少票数

枚举席位数,从0到sum

for(int i=1;i<=n;i++){
    for(int j=0;j<=sum;j++){
        //不获得第i场的席位
        f[i][j]=f[i-1][j];
        //获得第i场的席位
        if(a[i]>b[i]&&j-c[i]>=0) f[i][j]=min(f[i][j],f[i-1][j-c[i]]+0);//如果a[i]本来就大于b[i],那么不需要转移票数,直接获得席位,从j-c[i]转移到j,加0表示不需要转移票
        else if(a[i]<=b[i]&&j-c[i]>=0) f[i][j]=min(f[i][j],f[i-1][j-c[i]]+(b[i]-a[i])/2+1);//由于该场获得了c[i],所以从j-c[i]转移到j,最少需要转移的票数为(b[i]-a[i])/2+1
    }
}

这样的话,需要f[100][1e7],这样就爆空间了,所以优化为一维 

for(int i=1;i<=n;i++){
    for(int j=sum;j>=c[i];j--){
        if(a[i]>b[i]) f[j]=min(f[j],f[j-c[i]]+0);//如果a[i]本来就大于b[i],那么不需要转移票数,直接获得席位,从j-c[i]转移到j,加0表示不需要转移票
        else if(a[i]<=b[i]) f[j]=min(f[j],f[j-c[i]]+(b[i]-a[i])/2+1);//由于该场获得了c[i],所以从j-c[i]转移到j,最少需要转移的票数为(b[i]-a[i])/2+1
    }
}

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#define endl '\n'
#define int long long
using namespace std;
typedef long long ll;
const int N=110,M=1e7+10;
int a[N],b[N],c[N];
int f[M];
int n;
void solve() {
    cin>>n;
    int sum=0;
    for(int i=1; i<=n; i++) {
        cin>>a[i]>>b[i]>>c[i];
        sum+=c[i];
    }
    memset(f,0x3f,sizeof f);
    f[0]=0;
    for(int i=1; i<=n; i++) {
        for(int j=sum; j>=c[i]; j--) {
            if(a[i]>b[i]) f[j]=min(f[j],f[j-c[i]]+0);//如果a[i]本来就大于b[i],那么不需要转移票数,直接获得席位,从j-c[i]转移到j,加0表示不需要转移票
            else if(a[i]<=b[i]) f[j]=min(f[j],f[j-c[i]]+(b[i]-a[i])/2+1);//由于该场获得了c[i],所以从j-c[i]转移到j,最少需要转移的票数为(b[i]-a[i])/2+1
        }
    }
    int ans=1e18;
    //枚举席位数大于半数时最少需要转移的票数
    for(int i=(sum+1)/2;i<=sum;i++){
        ans=min(ans,f[i]);//一直取min就行了,某些席位i可能组成不了(因为席位都是一个个离散的数,不是连续的),则f[i]为无穷大
    }
    cout<<ans<<endl;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}

E - Avoid Eye Contact (atcoder.jp)

最短路,用bfs

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=2010;
char s[N][N];
int vis[N][N];//标记是否可走以及是否走过
int h,w;
int x,y;
int dx[4]= {-1,1,0,0},dy[4]= {0,0,-1,1};
struct node {
    int x,y;
    int d;
};
queue<node>q;
int bfs() {
    q.push({x,y,0});
    s[x][y]='#';
    while(q.size()) {
        auto t=q.front();
        q.pop();
        int x=t.x,y=t.y,d=t.d;
        for(int i=0; i<4; i++) {
            int tx=x+dx[i],ty=y+dy[i];
            if(tx<1||tx>h||ty<1||ty>w) continue;
            if(vis[tx][ty]==1||s[tx][ty]=='#') continue;
            if(s[tx][ty]=='G') return d+1;
            if(s[tx][ty]='.') {
                q.push({tx,ty,d+1});
                s[tx][ty]='#';
            }
        }
    }
    return -1;
}
void solve() {
    cin>>h>>w;
    for(int i=1; i<=h; i++) {
        for(int j=1; j<=w; j++) {
            cin>>s[i][j];
            if(s[i][j]=='S') {
                x=i;
                y=j;
            }
        }
    }
    //预处理障碍
    for(int i=1; i<=h; i++) {
        for(int j=1; j<=w; j++) {
            if(s[i][j]=='^') {
                vis[i][j]=1;
                int k=i-1;
                while(k>=1&&(s[k][j]=='.'||s[k][j]=='S'||s[k][j]=='G')) {
                    vis[k][j]=1;
                    k--;
                }
            } else if(s[i][j]=='v') {
                vis[i][j]=1;
                int k=i+1;
                while(k<=h&&(s[k][j]=='.'||s[k][j]=='S'||s[k][j]=='G')) {
                    vis[k][j]=1;
                    k++;
                }
            } else if(s[i][j]=='<') {
                vis[i][j]=1;
                int k=j-1;
                while(k>=1&&(s[i][k]=='.'||s[i][k]=='S'||s[i][k]=='G')) {
                    vis[i][k]=1;
                    k--;
                }
            } else if(s[i][j]=='>') {
                vis[i][j]=1;
                int k=j+1;
                while(k<=w&&(s[i][k]=='.'||s[i][k]=='S'||s[i][k]=='G')) {
                    vis[i][k]=1;
                    k++;
                }
            }
        }
    }
//    cout<<endl;
//    for(int i=1;i<=h;i++){
//        for(int j=1;j<=w;j++){
//            cout<<vis[i][j];
//        }
//        cout<<endl;
//    }
    cout<<bfs()<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值