The 2024 ICPC Asia Shenyang Regional Contest (The 3rd Universal Cup. Stage 19: Shenyang) E. Light Up the Grid

首先可以用 0~15 中的数字来表示某种特定的状态,而所求的解即为,要经过所有给出状态的补集。
操作对应的是不同状态间的转移,那么可以通过 Floyd 求出任意两状态转移间的花费。
然后 m 只有 16 考虑状压,设 f(S,i) 表示操作的序列已经经过的状态为 S,最后一次操作完,操作序列之和对应的状态为 i 的最小花费。
这样会有一个问题就是如果给的状态里有 1111 就会错误,考虑特殊处理一下 (0,0)f(S|1,i),即为,如果 S 中有 1 ,那么必须要求是其第二次经过 1 才可以。
最后统计答案时,对于每一种状态求其补集,在将这些数状压得到对应的集合。答案即为 minf(S,i)

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define N 28
#define lowbit(x) x&-x
#define int long long
using namespace std;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
	return x*f;
}
char s[5];
int T,m,a0,a1,a2,a3,ans,f[N][N],b[N],a[N][5],g[1<<16][16],c[N][N];
int ID(int a,int b,int c,int d)
{
	return a*8+b*4+c*2+d;
}
signed main()
{
    #ifdef LOCAL
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif
	T=read();a0=read();a1=read();a2=read();a3=read();
	
	memset(g,0x3f,sizeof(g));
	memset(f,0x3f,sizeof(f));
	memset(c,0x3f,sizeof(c));
	for(int i=0;i<(1<<4);i++)
	{
		int D=i%2,C=(i%4)/2,B=(i%8)/4,A=i/8;
		// cout<<i<<" "<<A<<B<<C<<D<<endl;
		c[i][ID(A^1,B,C,D)]=min(c[i][ID(A^1,B,C,D)],a0);
		c[i][ID(A,B^1,C,D)]=min(c[i][ID(A,B^1,C,D)],a0);
		c[i][ID(A,B,C^1,D)]=min(c[i][ID(A,B,C^1,D)],a0);
		c[i][ID(A,B,C,D^1)]=min(c[i][ID(A,B,C,D^1)],a0);
		c[i][ID(A^1,B^1,C,D)]=min(c[i][ID(A^1,B^1,C,D)],a1);
		c[i][ID(A^1,B,C^1,D)]=min(c[i][ID(A^1,B,C^1,D)],a2);
		c[i][ID(A,B^1,C,D^1)]=min(c[i][ID(A,B^1,C,D^1)],a2);
		c[i][ID(A,B,C^1,D^1)]=min(c[i][ID(A,B,C^1,D^1)],a1);
		c[i][ID(A^1,B^1,C^1,D^1)]=min(c[i][ID(A^1,B^1,C^1,D^1)],a3);
	}
	for(int i=1;i<=15;i++)f[i][i]=0;
	f[0][0]=min(a0,min(a1,min(a2,a3)))*2;
	for(int i=0;i<=15;i++)
	{
		for(int j=0;j<=15;j++)
		{
			f[i][j]=min(f[i][j],c[i][j]);
		}
	}
	for(int k=0;k<=15;k++)
	{
		for(int i=0;i<=15;i++)
		{
			for(int j=0;j<=15;j++)
			{
				f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
			}
		}
	}
	for(int i=0;i<=15;i++)
	{
		g[1<<i][i]=f[0][i];
	}
	for(int S=2;S<(1<<16);S++)
	{
		for(int j=0;j<=15;j++)
		{
			if(((1<<j)&S)==0)continue;
			for(int k=0;k<=15;k++)
			{
				if(j==k||(S&(1<<k))==0)continue;
				g[S][k]=min(g[S][k],g[S^(1<<k)][j]+f[j][k]);
			}
		}
	}
	while(T--)
	{
		m=read();
		int S=0;
		for(int i=1;i<=m;i++)
		{
			cin>>(s+1);
			a[i][0]=s[1]-'0';a[i][1]=s[2]-'0';
			cin>>(s+1);
			a[i][2]=s[1]-'0';a[i][3]=s[2]-'0';
			int x=0;
			for(int j=0;j<=3;j++)x=(x<<1)+a[i][j];
			S|=(1<<(15-x));
		}
		int ans=1e18;
		for(int i=0;i<=15;i++)ans=min(ans,g[S][i]);
		printf("%lld\n",ans);
	}
}
posted @   shao0320  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2021-02-09 AtCoder Beginner Contest 190
****************************************** 页脚Html代码 ******************************************
点击右上角即可分享
微信分享提示