2015南阳CCPC部分题目代码

我是部分按照难度来排序的,越简单的越前面。


首先是L题。

#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
    int t;scanf("%d",&t);
    for(int s = 1;s <= t;s ++)
    {
        int n;
<span style="white-space:pre">	</span>scanf("%d",&n);
        printf("Case #%d: %d\n",s,2*n-1);//为什么是这个呢?(虽然我想了蛮久T^T这就是大神与渣渣的区别)很简单。因为你要能够从两边辨认出不同药的话你就必须两边的要要一模一样,而这时总数就必须奇数,否则找不到中心在哪里。
    }
    return0;
}


接下来是A题,其实看完A题,一种心酸感油然而生,好裸地一道模板题啊,就是给两个矩阵,然后对其中一个矩阵进行转置,判断两个矩阵可不可能相等。。。二话不说上代码。

#include<bits/stdc++.h>
#define LL long long
#define PI acos(-1.0)
#define eps 1e-5
using namespace std;
int a[5][5];
int b[5][5];
int n;
void Rotation1() {
    int i, j;
    int tmp[31][31];//局部变量,函数调用完后会自动释放  
    int dst = n - 1;    //这里我们从目标矩阵的最后一列开始存放数据  
    //顺时针旋转矩阵90度  
    for (i = 0; i<n; i++, dst--) 
        for (j = 0; j<n; j++)
        tmp[j][dst] = b[i][j];
    //将旋转后的矩阵保存回原来的矩阵  
    for (i = 0; i<n; i++) 
        for (j = 0; j<n; j++)
         b[i][j] = tmp[i][j];
}
int main(){
	int t;
	int cs = 1;
	scanf("%d",&t);
    while(t--){
        for(int i=0;i<2;++i)
            for(int j=0;j<2;++j)
                scanf("%d",&a[i][j]);
        for(int i=0;i<2;++i)
            for(int j=0;j<2;++j)
                scanf("%d",&b[i][j]);
        int ans=0,maxn=-1;
        for(int i=0;i<2;++i){//0
            for(int j=0;j<2;++j){
                if(a[i][j]==b[i][j])
                    ans++;
            }
        }
        n=2;
        maxn=max(maxn,ans);
        ans=0;
        Rotation1(); 
        for(int i=0;i<2;++i){//90
            for(int j=0;j<2;++j){
                if(a[i][j]==b[i][j])
                    ans++;
            }
        }
        maxn=max(maxn,ans);
        ans=0;
        Rotation1();
        for(int i=0;i<2;++i){//180
            for(int j=0;j<2;++j){
                if(a[i][j]==b[i][j])
                    ans++;
            }
        }
        maxn=max(maxn,ans);
        ans=0;
        Rotation1();
        for(int i=0;i<2;++i){//270
            for(int j=0;j<2;++j){
                if(a[i][j]==b[i][j])
                    ans++;
            }
        }
        maxn=max(maxn,ans);
        if(maxn == 4)
			printf("Case #%d: POSSIBLE\n",cs++);
		else
			printf("Case #%d: IMPOSSIBLE\n",cs++);
    }
	return 0;
}


接下来就是G题

其实G题也并不难,就是你只要找到一个‘.’,让他满足当这个点被'x'覆盖的时候有'o'从棋盘上被移除。这里就有两种方法,第一是直接暴力遍历,毕竟是9x9的棋盘,只要对该棋盘内的‘.’dfs一遍,看看该点是不是满足当这个点被'x'覆盖的时候有'o'从棋盘上被移除。第二种方法我用的是广搜,就是对于每一个‘o',我都对它进行遍历,看它周围是否只有1个’.‘。

以下是代码。

#include<bits/stdc++.h>
using namespace std;
int dir[][2]={0,1,0,-1,1,0,-1,0};
char ch[12][12];
bool vis[12][12];
struct node
{
    int x,y;
};
int bfs(node s)
{
    int ans = 0;
    queue<node>q;
    q.push(s);
    memset(vis,false,sizeof(vis));
    vis[s.x][s.y] = true;
    while(!q.empty())
    {
        node now = q.front();
        q.pop();
        for(int i=0;i<4;++i)
        {
            node aa;
            aa.x = now.x + dir[i][0];
            aa.y = now.y + dir[i][1];
            if(aa.x>=0 && aa.x<9 && aa.y>=0 && aa.y<9 && ch[aa.x][aa.y] != 'x')
            {
                if(ch[aa.x][aa.y] == '.')
                {
                    if(vis[aa.x][aa.y] == false)
                        ans++;
                    vis[aa.x][aa.y] = true;
                }
                else//这里如果是'o'那么就要顺着它向下找,因为被吃掉的棋子可能不止一个。
                {
                    if(vis[aa.x][aa.y] == false)
                    {
                        vis[aa.x][aa.y] = true;
                        q.push(aa);
                    }
                }
            }
            else
                continue;
        }
    }
    if(ans > 1)//说明它周边的'.'不止一个,没法在一步之后把它吃掉。
        return 0;
    else
        return 1;
}
int main() {
    int t;
    scanf("%d%*c",&t);
    int x = 1;
    while(t--)
    {
        for(int i=0;i<9;++i)
        {
            scanf("%s",ch[i]);
        }
        bool flag = false;
        for(int i=0;i<9;++i)
        {
            for(int j=0;j<9;++j)
            {
                if(ch[i][j] == 'o')
                {
                    node st;
                    st.x = i,st.y = j;
                    if(bfs(st))
                    {
                        flag = true;
                        break;
                    }
                }
            }
            if(flag)
                break;
        }
        if(flag)
            printf("Case #%d: Can kill in one move!!!\n",x++);
        else
            printf("Case #%d: Can not kill in one move!!!\n",x++);
    }
    return 0;
}
上面那份代码是广搜版的,还有深搜版的,不过深搜版的要写两个dfs,一个用来判断'o'点的连续,而另一个则要判断所有的点,其中深搜的时候要注意当前位置恢复到初始的状态。这里我就不贴代码了。



接下来是D题。不过南阳的D题简直逗我玩,我想了好久才有大概思路。。。哎~~~dp没过关的伤不起啊。

思路其实还好,就是要考虑浮点数问题,当然一般选择长度加倍来避免出现浮点数误差。然后呢就是状态转移方程了。这个状态转移方程有点难推。
首先呢题目中告诉你只要一半及以上的长度在容器内是可以的,那么一个问题就产生了,那就是你在放的过程中可以有多少根金条是可以超出边界的,答案很简单,0、1、2这三种。

其次样例中也出现了特例(个人理解为特例),那就是只有一根金条的时候是一定可以的,那么只要特判一下就好。

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int l;
    long long val;
}str[1100];
long long dp[5000][3];//dp[i][j]表示长度为i的木板上,其中有j个金条放在边沿部分 
int main()
{
    int t;
    scanf("%d",&t);
    int cas = 1;
    while(t--)
    {
        long long n,l,ans = -1;
        scanf("%I64d %I64d",&n,&l);
        l *= 2;//为了防止浮点误差特意加倍
        for(int i = 1;i <= n;i++)
        {
            scanf("%d %I64d",&str[i].l,&str[i].val);
            str[i].l *= 2;//为了防止浮点误差特意加倍 
        }
        if(n==1)//特判一下只有一根金条的情况 
        {
            printf("Case #%d: %I64d\n",cas++,str[1].val);
            continue;
        }
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;++i)//开始dp 
        {
            for(int j=l;j>=str[i].l/2;--j)
            {
                for(int k=0;k<=2;++k)
                {
                    if(j>=str[i].l)//当木板长度大于这根金条的长度时,直接放进去就好。 
                        dp[j][k] = max(dp[j][k],dp[j-str[i].l][k]+str[i].val);
                    if(j>=str[i].l/2 && k>0)//当有一部分要放在边沿时判断一下要放是一个边沿还是两个边沿 
                        dp[j][k] = max(dp[j][k],dp[j-str[i].l/2][k-1]+str[i].val);
                }
            }
        }
        for(int i=0;i<=l;++i)
        {
            for(int j=0;j<=2;++j)
            {
                ans=max(ans,dp[i][j]);
            }
        }
        printf("Case #%d: %I64d\n",cas++,ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值