2014 Super Training #4 D Paint the Grid Again --模拟

原题:ZOJ 3780 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3780

刚开始看到还以为是搜索题,没思路就跳过了。结果后来发现就是一个简单的模拟啊,因为每行每列都只能消去一次,直接慢慢消去就好了,因为按字典序从小到大,那就按行从大到小,列从大到小的顺序来消就可以了,消完了标记一下,把那行或者那列的元素都赋为一个特殊的字符‘*‘即可。

还是应该多思考啊,不要被题目吓到了。探寻题目的本质才能更好的解题。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
#define N 14

pair<char,int> ans[250020];
char ss[506][506];
int Rvis[506],Cvis[506];

int main()
{
    int t,n,i,j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=0;i<n;i++)
            scanf("%s",ss[i]);
        memset(Rvis,0,sizeof(Rvis));
        memset(Cvis,0,sizeof(Cvis));
        int flag = 0;
        int o,x,h;
        int k = 0;
        while(!flag)
        {
            flag = 1;
            //行X
            for(i=n-1;i>=0;i--)
            {
                if(Rvis[i])
                    continue;
                o = x = h = 0;
                for(j=0;j<n;j++)
                {
                    if(ss[i][j] == ‘X‘)
                        x++;
                    else if(ss[i][j] == ‘O‘)
                        break;
                    else
                        h++;
                }
                if(j == n && h != n)  //没有出现O且不全为‘*‘
                {
                    Rvis[i] = 1;
                    ans[k].first = ‘R‘;
                    ans[k++].second = i+1;
                    for(j=0;j<n;j++)
                        ss[i][j] = ‘*‘;
                    flag = 0;
                    break;
                }
                else if(h == n)
                    Rvis[i] = 1;
            }
            if(!flag)
                continue;
            //列O
            for(j=n-1;j>=0;j--)
            {
                if(Cvis[j])
                    continue;
                o = x = h = 0;
                for(i=0;i<n;i++)
                {
                    if(ss[i][j] == ‘X‘)
                        break;
                    else if(ss[i][j] == ‘O‘)
                        o++;
                    else
                        h++;
                }
                if(i == n && h != n) //没有出现X且不全为‘*‘
                {
                    Cvis[j] = 1;
                    ans[k].first = ‘C‘;
                    ans[k++].second = j+1;
                    for(i=0;i<n;i++)
                        ss[i][j] = ‘*‘;
                    flag = 0;
                    break;
                }
                else if(h == n)
                    Cvis[j] = 1;
            }
        }
        int tag = 1;
        for(i=0;i<n;i++)
            for(j=0;j<n;j++)
                if(ss[i][j] != ‘*‘)
                {
                    tag = 0;
                    break;
                }
        if(!tag)
            puts("No solution");
        else
        {
            printf("%c%d",ans[k-1].first,ans[k-1].second);
            for(i=k-2;i>=0;i--)
                printf(" %c%d",ans[i].first,ans[i].second);
            printf("\n");
        }
    }
    return 0;
}

2014 Super Training #4 D Paint the Grid Again --模拟

时间: 2024-10-22 10:51:54

2014 Super Training #4 D Paint the Grid Again --模拟的相关文章

2014 Super Training #1 F Passage 概率DP

原题: HDU 3366   http://acm.hdu.edu.cn/showproblem.php?pid=3366 本来用贪心去做,怎么都WA,后来看网上原来是一个DP题. 首先按P/Q来做排序,即P越大,Q越小就越好,这样可以确保先选最优的路走. dp[i][j]表示已经到了第i条路(说明前i-1条都没成功的情况),还剩j块钱时能够走出去的概率. 则方程: dp[i][j] = way[i].P + way[i].Q*(dp[i+1][j-1]) + way[i].D*(dp[i+1]

2014 Super Training #8 B Consecutive Blocks --排序+贪心

当时不知道怎么下手,后来一看原来就是排个序然后乱搞就行了. 解法不想写了,可见:http://blog.csdn.net/u013368721/article/details/28071241 其实就是滑动窗口的思想. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algor

2014 Super Training #1 C Ice-sugar Gourd 模拟,扫描线

原题 HDU 3363 http://acm.hdu.edu.cn/showproblem.php?pid=3363 给你一个串,串中有H跟T两种字符,然后切任意刀,使得能把H跟T各自分为原来的一半. 解法: 把串想象成一个环,只要满足H跟T都为偶数个,那么就可以做一条过圆心的直线把H跟T平分掉,过直线,只要考虑平分H或者T中的一个就可以了,因为直线本来就把环平分,而此时平分了H或者T,那么剩下的那个也是平分掉的. 具体证明: http://hi.baidu.com/superlong/item

2014 Super Training #1 B Fix 状压DP

原题: HDU 3362 http://acm.hdu.edu.cn/showproblem.php?pid=3362 开始准备贪心搞,结果发现太难了,一直都没做出来.后来才知道要用状压DP. 题意:题目给出n(n <= 18)个点的二维坐标,并说明某些点是被固定了的,其余则没固定,要求添加一些边,使得还没被固定的点变成固定的,可见题目中的图形sample. 由于n很小,而且固定点的顺序没有限制,所以需要用状态压缩DP. 注意:1.当一个没固定的点和两个固定了的点连接后,该点就被(间接)固定了(

2014 Super Training #3 H Tmutarakan Exams --容斥原理

原题: URAL 1091  http://acm.timus.ru/problem.aspx?space=1&num=1091 题意:要求找出K个不同的数字使他们有一个大于1的公约数,且所有的数字都不能大于一个指定的数字S. 解法:可以考虑每个S内的素数,此素数和它的所有倍数构成一个集合,则可以在这些集合中任意去k个元素,C(n,k)即为这种情况下的方法种数,比如K = 3,S = 10, 则可以形成3个集合: {2,4,6,8,10} , {3,6,9}, {5,10} ,第一个集合C(5,

2014 Super Training #8 A Gears --并查集

题意: 有N个齿轮,三种操作1.操作L x y:把齿轮x,y链接,若x,y已经属于某个齿轮组中,则这两组也会合并.2.操作Q x y:询问x,y旋转方向是否相同(等价于齿轮x,y的相对距离的奇偶性).3.操作D x :拆下齿轮x,并且x所在的齿轮组不会断开4.操作S x : 查询齿轮x所在的齿轮组有多少齿轮.并查集,维护父节点的同时,dis记录一下每个节点到根节点的距离,并且用num记录一下以x为根节点的集合有多少个元素. 由于涉及到删除操作,删除的是根节点的话会导致信息丢失,所以在删除的时候直

2014 Super Training #7 E Calculate the Function --矩阵+线段树

原题:ZOJ 3772 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3772 这题算是长见识了,还从没坐过矩阵+线段树的题目呢,不要以为矩阵就一定配合快速幂来解递推式的哦. 由F(x)=F(x-1)+F(x-2)*A[x],转化为矩阵乘法:  ===> 所以维护一颗线段树,线段树的每个结点保存一个矩阵,叶子节点为: a[0][0] = a[1][0] = 1, a[0][1] = Ax, a[1][1] = 0的形式

2014 Super Training #6 F Search in the Wiki --集合取交+暴力

原题: ZOJ 3674 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3674 题意不难理解,很容易想到用暴力,但是无从下手,不知道怎么实现.后来看了网上的代码,直接用vector和map暴力,用到了set_intersection()函数,之前也听过这个函数,但是一直没写过,于是照着他的代码打了一遍,算是见识一下这个函数了. 代码看一下就能看懂了,关键看自己能不能写出来. 代码: #include <iostream

2014 Super Training #7 B Continuous Login --二分

原题:ZOJ 3768 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3768 一个结论:一个正整数总能用不超过三个前n项相加表示. 先找一个的,在找两个,三个的,二分找,用lower_bound函数. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <