CUGBACM Codeforces Tranning 8解题报告

本文针对一场算法竞赛中的五道题目提供了详细的解题思路与AC代码。包括括弧匹配问题、最短路径问题、图连通性问题等,采用C++实现。

比赛链接点击打开链接

A题 

题意 给定一个由左右小括弧组成的串,通过删除某些括弧,求剩下的括弧能够获得的最长合法长度。

思路:类似求合法括弧的题目,之前做过一些,也有了一些经验。首先,从左往右扫,两个变量rest和cnt ,遇到“(” ,rest++,否则rest--,cnt++。若rest<0 说明这个括弧要删除。同理,从右往左再扫一遍。求两次的最大值即可。

开始的时候没读清题意,以为是老题WA了。。。

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll ;
const int inf = 1<<29;
char a[1000005];
int main()
{
    cin>>a;
    int n=strlen(a),i;
    int cnt1=0,cnt2=0;
    int rest=0;
    for(i=0; i<n; i++)
    {
        if(a[i]=='(')
        {
            rest++;
        }
        else if(a[i]==')')
        {
            rest--;
            if(rest>=0)
            {
                cnt1++;
            }
        }
        if(rest<0)
        {
            rest=0;
        }
    }
    rest=0;
    for(i=n-1; i>=0; i--)
    {
        if(a[i]==')')
        {
            rest++;
        }
        else if(a[i]=='(')
        {
            rest--;
            if(rest>=0)
            {
                cnt2++;
                rest--;
            }
        }
        if(rest<0)
        {
            rest=0;
        }
    }
    cout<<max(cnt1,cnt2)*2<<endl;
    return 0;
}

B题

题意:给定一个矩阵d,d[i][j]代表初始i和j之间的最短路。现在要在某些点间建一些新的路径。求建到第i条路径时,任意两点之间最短路的和。

用类似floyed求最短路的思想。简单回顾一下floyed求最短路。其基本思想是dp,对于从i到j的路径,走点k和不走点k。那么这道题从i到j,对于新建的路,走还是不走。

注意输入数据中,新建的路有可能比之前的路要长。

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll ;
const int inf = 1<<29;
const int maxn=305;
int d[maxn][maxn];
int main()
{
    int n,m,i,j,a,b,c;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
            cin>>d[i][j];
    }
    cin>>m;
    while(m--)
    {
        cin>>a>>b>>c;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                d[j][i]=d[i][j]=min(d[i][j],d[i][a]+d[b][j]+c);
                d[j][i]=d[i][j]=min(d[i][j],d[i][b]+d[a][j]+c);
            }
        }
        ll ans=0;
        for(i=1;i<=n;i++)
        {
            for(j=i+1;j<=n;j++)
            {
                ans+=d[i][j];
            }
        }
        cout<<ans<<" ";
    }
    return 0;
}

C题 

题意 输入一些路径。让你删除一些路径的同时再添加一些路径,使得每两个点之间都可以到达。

思路:并查集。输入路径时,判断两点是否处于同一个集合,若在,当前这条路就可以删除。否则,这条路径就要保留。

然后再枚举两个任意点,判断是否在同一个集合中,若不在,两个点之间建路。

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll ;
const int inf = 1<<29;
const int maxn=1005;
int del[maxn][2],add[maxn][2];
int parent[maxn];
void init(int n)
{
    for(int i=1;i<=n;i++)
        parent[i]=i;
}
int find_p(int p)
{
    if(p==parent[p]) return p;
    return parent[p]=find_p(parent[p]);
}

int main()
{
    int n,i,j,x,y,cnt1=0,cnt2=0;
    cin>>n;
    init(n);
    for(i=1;i<n;i++)
    {
        cin>>x>>y;
        int fx=find_p(x),fy=find_p(y);
        if(fx!=fy)
            parent[fx]=fy;
        else
        {
            del[cnt1][0]=x,del[cnt1++][1]=y;
        }
    }
    for(i=1;i<=n;i++)
    {
        for(j=i+1;j<=n;j++)
        {
             int fi=find_p(i),fj=find_p(j);
             if(fi!=fj)
             {
                 parent[fi]=fj;
                 add[cnt2][0]=fi,add[cnt2++][1]=fj;
             }

        }
    }
    cout<<cnt1<<endl;
    for(i=0;i<cnt1;i++)
    {
        cout<<del[i][0]<<" "<<del[i][1]<<" "<<add[i][0]<<" "<<add[i][1]<<endl;
    }
    return 0;
}


D题 机智题

题意:为了说清楚题意,我增加一个时间t。题意是这样的:t=0时,有零个朋友的人全部滚蛋。t=1时,对于剩下的人而言,有1个朋友的全部滚蛋……问最终人数稳定时,最多可能剩下多少人。

思路:因为时间是每次加1的。对于当前t,认识t+1个朋友的不会离开。这些人要想在t+1秒不离开,他们认识的人数就要发生突变,必然变成比t+1小的数,显然t-1是最大的数。对于n个人来说,显然n-2最大。那么怎么实现这种突变呢?假设1,2不认识,并且与n-2个人都认识,剩下n-2个人认识n-1个人,那么当t=n-2时,1和2走了,那么剩下的n-2个人瞬间从认识n-1个人变成认识n-3个人。当t=n-1时,已经没有认识n-1个人的人了。

因此,最终结果就是n-2,特判一下1就好。

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll ;
const int inf = 1<<29;
int main()
{
    int n;
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n;
        if(n==1) cout<<0<<endl;
        else cout<<n-2<<endl;
    }
    return 0;
}

E题

先来WA个坑。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值