HDU 5600 || HDU 5601 思维

HDU 5600
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5600
题意:
自己的解法:
给一行的n个数的01序列,1表示第i个灯泡开着。
现在从1出发,从n离开,且可以往返走,每次离开一个灯泡,灯泡的状态发生改变。
问存不存在一种解法,使得离开时,灯泡全灭。
思路:
用几个样例模拟了一下,对于前一个数,总能通过后一个数的变化使得前一个状态为0。对于后一个数,前一个数和它不同时,后一个数为1。然后一步步往后遍历就可以。
那么,进一步简化,0个个数是偶数就可以。

标解:
一次走到头,所有0变1,1变0。
然后往回走。由于一条回路中只有首尾两个点的状态有变化,所以往回遍历所有状态为1的点,然后遍历完看看第n个点是否为1即可。
源码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 1000000 + 5;
int data[MAXN];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        int n;
        scanf("%d", &n);
        for(int i = 1 ; i <= n ; i++)   scanf("%d", &data[i]);
        if(n == 1){
            if(data[1] == 1)    printf("YES\n");
            else    printf("NO\n");
            continue;
        }
        int num = 0;
        for(int i = 1 ; i <= n ; i++){
            if(data[i] == 0)    num++;
        }
//        for(int i = 1 ; i <= n ; i++)   printf("%d ", data[i]);
//        printf("\n");
        if(num % 2 == 0)    printf("YES\n");
        else    printf("NO\n");
    }
    return 0;
}

HDU 5601
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5601
题意:
给n*m的01序列,1表示第i个灯泡开着。
现在从1出发,从n离开,且可以往返走,每次离开一个灯泡,灯泡的状态发生改变。
问存不存在一种解法,使得离开时,灯泡全灭。
思路:
Solution1:
标解。
发现斜着走是可以做到不改变任何灯泡的状态的,比如1-2-1-2-3,其中1和3在一条斜线上。
进而把所有格子进行染色,行数加列数为奇数的一个颜色,偶数一个颜色。
也就是说,如果消除一个1,就需要变一次色。
那么,最后需要从(n,m)这个点走出去,也就是说要走到形如(n+1,m)的这个点。
也就是说,1的个数和n+m+1同奇偶就输出YES。
Solution2:
自己的解法。
先从第一行到最后一行。
到一行时,如果右边有1,按照HDU5600的标解的走法把1消除,然后根据消除的次数变化a[i][1]的状态。
到下一行时,根据上一行第一列的此时状态和当前行的1的个数变化此行第一列这个数。
然后变化到最后一行,就转换成HDU5600了。
源码:
Solution1:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 1000 + 5;
int g[MAXN][MAXN];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        int n, m;
        scanf("%d%d", &n, &m);
        int cnt = 0;
        for(int i = 1 ; i <= n ; i++){
            for(int j = 1 ; j <= m ; j++){
                scanf("%d", &g[i][j]);
                if(g[i][j] == 1)    cnt++;
            }
        }
        if(cnt % 2 == (n + m + 1) % 2)  printf("YES\n");
        else    printf("NO\n");
    }
    return 0;
}

Solution2:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 1000 + 5;
int g[MAXN], cnt[MAXN];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        memset(g, 0, sizeof(g));
        memset(cnt, 0, sizeof(cnt));
        int n, m;
        scanf("%d%d", &n, &m);
        int u;
        for(int i = 1 ; i <= n ; i++){
            for(int j = 1 ; j <= m ; j++){
                scanf("%d", &u);
                if(j == 1)  g[i] = u;
                else if(u == 0) cnt[i]++;
            }
        }
        for(int i = 1 ; i < n ; i++){
            int temp = (m - 1 - cnt[i]) + 1;
            if((temp + g[i]) % 2 != 0)   g[i + 1] = (g[i + 1] + 1) % 2;
        }
        if(((g[n] + 1) % 2 + cnt[n]) % 2 == 0) printf("YES\n");
        else    printf("NO\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值