hdu 5386 Cover 脑洞 +有点贪心 2015 Multi-University Training Contest 8

Cover

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1184    Accepted Submission(s): 411
Special Judge


Problem Description
You have an  nn  matrix.Every grid has a color.Now there are two types of operating:
L x y: for(int i=1;i<=n;i++)color[i][x]=y;
H x y:for(int i=1;i<=n;i++)color[x][i]=y;
Now give you the initial matrix and the goal matrix.There are  m  operatings.Put in order to arrange operatings,so that the initial matrix will be the goal matrix after doing these operatings

It's guaranteed that there exists solution.
 

Input
There are multiple test cases,first line has an integer  T
For each case:
First line has two integer  n , m
Then  n  lines,every line has  n  integers,describe the initial matrix
Then  n  lines,every line has  n  integers,describe the goal matrix
Then  m  lines,every line describe an operating

1color[i][j]n
T=5
1n100
1m500
 

Output
For each case,print a line include  m  integers.The i-th integer x show that the rank of x-th operating is  i
 

Sample Input
  
  
1 3 5 2 2 1 2 3 3 2 1 3 3 3 3 3 3 3 3 3 3 H 2 3 L 2 2 H 3 3 H 1 3 L 2 3
 

Sample Output
  
  
5 2 4 3 1
 

Author
SXYZ
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5395  5394  5393  5392  5391 

用顺序性解决问题,从开始状态考虑反而不好考虑,从结束情况倒推好考虑。
这是因为,如果从开始考虑,贴了一个,就会影响使用过的操作,可能会造成有些地方需要却不够。
如果从结果考虑,如果m个操作中某个位置没有出现过,那么那个位置一定不用贴,
如果出现过了,那么首先把符合最后情况的考虑进去,然后倒着考虑,这样最后的结果是对的,无论怎么贴贴过的位置都是符合的。
而且这样一定能保证正确:
1.首先这样贴是必须的,不论开始的状态如何,假如有某一行有n种贴法,现在有x种与结果不同,y种与结果相同,只要是把某种与结果不同的放到最后都是错的,所以一直要把所有的y全部放到最后才行  。 (这是必须性)(ps:假如y=0,就一定有x=0,因为保证有解)
而且只要放了第一个y到最后,不论是哪一个操作,这个位置其余的随便贴。

2.
(一定有解性)题目说一定有解,就是说每个操作一定能安排一个恰当的位置,即使倒着考虑现在暂时不能贴,那以后也一定可以贴。
 (没有相互影响)因为每次操作是对同一行或同一列的多个位置贴,只要当前操作对某个位置不合适就不能贴,(这个操作一定有办法再之后贴进去,证明这个操作对某一个位置来说是x,那么一定有y,先贴y),先找能贴的贴。假如说没有一个操作能贴,那是不可能的,因为保证有解。
(所以某一操作能贴近去,它覆盖的所有位置必须与结果相同或是已经贴过了)
3.综合考虑,贴法是必须的,而且每个操作都一定能安排到一个合适的顺序位置,另加倒着想当前步一定有操作可做,那么这样做一定是正确的。

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n)  for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n)  for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n)  for(int i=(n) ;i>=0 ;i--)
#define  lson   num<<1,le,mid
#define rson    num<<1|1,mid+1,ri
#define MID   int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)

using namespace std;
const int INF =0x3f3f3f3f;
const int maxn= 100+10   ;
const int maxm= 500+10   ;
//const int INF=    ;
typedef long long ll;
const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
//by yskysker123
int n,m;
int st[maxn][maxn];
int ed[maxn][maxn];
int ans[maxm];
struct kk
{
    char op;
    int x;//x表示第x行或第x列
    int y;
    int id;//操作序号
    kk () {}
    kk (char o,int xx,int yy,int id_):op(o),x(xx),y(yy),id(id_){}
    bool operator<(const kk x) const  //用set必须给出一个排序方法
    {
        return id<x.id;
    }
}  ;
multiset< kk > se;
int cnt;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {

        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&st[i][j]);
            }
        }
        for(int i=1;i<=n;i++)
        {
              for(int j=1;j<=n;j++)
             {
                 scanf("%d",&ed[i][j]);
             }
        }
        int x,y;
        char op;
        for(int i=1;i<=m;i++)
        {
            scanf(" %c%d%d",&op,&x,&y);
            se.insert(kk (op,x,y,i) );

        }

    cnt=m;
    set<kk>::iterator  it;
    while(!se.empty())
    {
        for(it=se.begin() ;  it!=se.end();it++)
        {
            int x=it->x;
            int y=it->y;
            int id=it->id;
            if(it->op=='H')
            {
                int i;
                for( i=1;i<=n;i++)
                {
                    if( !(ed[x][i]==0||ed[x][i]==y)  )    break;
                }
                if(i!=n+1)  continue;
                for( i=1;i<=n;i++)
                {

                        ed[x][i]=0;

                }
                se.erase(it);
                 ans[cnt--]=id;
                break;
            }
            else
            {
                int i;
                for( i=1;i<=n;i++)
                {
                    if(  !(ed[i][x]==0||ed[i][x]==y)   )  break;
                }
                if(i!=n+1)  continue;
                for( i=1;i<=n;i++)
                {
                    ed[i][x]=0;
                }
                se.erase(it);
                ans[cnt--]=id;
                break;

            }
        }

    }
    printf("%d",ans[1]);
    for(int i=2;i<=m;i++)
    {
        printf(" %d",ans[i]);
    }
    putchar('\n');

    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值