zoukankan      html  css  js  c++  java
  • 【CF1567F】One-Four Overload

    题目

    题目链接:https://codeforces.com/contest/1567/problem/F
    一张 (n imes m) 的网格,网格上有 .X。保证所有 X 都不与网格边缘相邻。给 . 赋值为 (1)(4)X 赋值为 (0,5)(10),求任意一种方案,使得每一个 X 的权值都等于它相邻的 . 权值之和。
    (n,mleq 500)

    思路

    很显然只有当 X 四周有偶数个 . 才有解。
    如果 X 周围只有两个 .,那么直接把这两个 . 连边,然后黑白染色即可。
    如果 X 周围有四个 .,猜了一个结论:存在一个上下两个 . 权值相同,左右两个 . 权值相同的解。
    手玩了一下感性理解的。我也不知道怎么证((。官方题解没看。
    时间复杂度 (O(nm))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=510,M=1000010;
    const int dx[]={0,0,0,1,-1},dy[]={0,1,-1,0,0};
    int n,m,tot,a[N][N],b[M],head[M],pos[3];
    bool flag;
    char ch;
    
    struct edge
    {
    	int next,to;
    }e[M];
    
    int ID(int x,int y)
    {
    	return (x-1)*m+y;
    }
    
    void add(int from,int to)
    {
    	e[++tot]=(edge){head[from],to};
    	head[from]=tot;
    	swap(from,to);
    	e[++tot]=(edge){head[from],to};
    	head[from]=tot;
    }
    
    void dfs(int x,int val)
    {
    	b[x]=val;
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (!b[v]) dfs(v,5-val);
    		if (b[x]==b[v]) flag=1;
    		if (flag) return;
    	}
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    		{
    			while (ch=getchar())
    				if (ch=='.' || ch=='X') break;
    			if (ch=='X') a[i][j]=1;
    		}
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			if (a[i][j])
    			{
    				int sum=4;
    				for (int k=1;k<=4;k++) 
    					sum-=a[i+dx[k]][j+dy[k]];
    				if (sum&1) return printf("NO"),0;
    				if (sum==2)
    				{
    					int tp=0;
    					for (int k=1;k<=4;k++)
    						if (!a[i+dx[k]][j+dy[k]]) pos[++tp]=ID(i+dx[k],j+dy[k]);
    					add(pos[1],pos[2]);
    				}
    				if (sum==4)
    				{
    					add(ID(i-1,j),ID(i,j-1)); add(ID(i-1,j),ID(i,j+1));
    					add(ID(i+1,j),ID(i,j-1)); add(ID(i+1,j),ID(i,j+1));
    				}
    			}
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			if (!a[i][j] && !b[ID(i,j)]) dfs(ID(i,j),1);
    	if (flag) return printf("NO"),0;
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			if (a[i][j])
    				for (int k=1;k<=4;k++)
    				{
    					int x=i+dx[k],y=j+dy[k];
    					if (!a[x][y]) b[ID(i,j)]+=b[ID(x,y)];
    				}
    	cout<<"YES
    ";
    	for (int i=1;i<=n;i++)
    	{
    		for (int j=1;j<=m;j++)
    			cout<<b[ID(i,j)]<<" ";
    		cout<<"
    ";
    	}
    	return 0;
    }
    
  • 相关阅读:
    Win11安装跳过TPM的方法 Win11安装怎么跳过TPM
    选取文件,列举文件(含子文件夹),记录大小信息,限制文件层级
    选取文件夹,枚举文件及子文件夹
    数据库SQL中having和where的用法区别
    Environ 函数调用系统环境变量 电脑用户名等
    Notepad++正则表达式语法
    VB几种函数参数传递方法,Variant,数组,Optional,ParamArray
    Access导出到Excel方法汇总
    VBA编程自动导出生成Excel表
    LeetCode 136 只出现一次的数字
  • 原文地址:https://www.cnblogs.com/stoorz/p/15232424.html
Copyright © 2011-2022 走看看