zoukankan      html  css  js  c++  java
  • 【BZOJ3003】LED BFS+状压DP

    【BZOJ3003】LED

    Description 

    LED屏是由一个庞大的点阵小灯泡组成的,一开始每个小灯泡都不发光。每一行一共有N个小灯泡,依次标号为1~n。现在给定K个点,要求这K个点发光,其余点必须保持熄灭状态。而这块LED屏的操作方式各种奇葩,一共有L种操作方法,第i种表示你能将任意长度恰为A_i的连续一段灯泡的状态取反(灭变亮,亮变灭)。
    已知LED屏一共有m行,为了节省时间,请你算出每一行达到目标状态所需的最少操作次数。

    Input

        输入文件第一行一个数m,表示LED屏的行数。
        对于LED屏的每一行:
        第一行为n,k,l,意义见上。
        第二行为k个数,表示要求发光的k个点。
        第三行为l个数,表示l种操作方式。

    Output

        对于LED屏的每一行:如果无法达到目标状态,输出-1,否则输出最少次数。

    Sample Input

    2
    10 8 2
    1 2 3 5 6 7 8 9
    3 5
    3 2 1
    1 2
    3

    Sample Output


    2
    -1
    【数据规模】
    对于100%的数据,T≤10,N≤10000,K≤10,L≤100,1≤A_i≤N。

    题解:一开始想网络流想了半天。。。结果是错的。

    第一步很常用也很关键,我们将原序列差分,然后就变成了只有2k个关键点需要染黑,而每个操作可以看成是将两个距离为L的格子同时反色。这个过程比较类似于一个最短路的过程,我们将一个关键点染色,此时出现了一个多余的点,我们再将多余点不断反色直到走到了另一个关键点,此时我们可以看做这两个关键点成功配对,而代价就是从这个点走到另一个点的最短路。所以我们先预处理出任意两个关键点之间的最短路,然后DP。

    设f[S]表示已经配对的点的状态为S的最小代价。转移时,我只需要们枚举S中最后那个点和谁配对即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <algorithm>
    using namespace std;
    int n,m,K,L;
    bool vis[10010];
    int op[30],w[30],v[110],dis[10010],f[30][30],g[1<<20],Log[1<<20];
    queue<int> q;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    inline void work()
    {
    	n=rd(),K=rd(),L=rd(),m=0;
    	memset(f,0x3f,sizeof(f)),memset(g,0x3f,sizeof(g));
    	int i,j,a,u;
    	for(i=1;i<=K;i++)
    	{
    		op[i]=rd();
    		for(j=1;j<i;j++)	if(op[j]==op[i])	break;
    		if(j==i)	vis[op[i]]^=1,vis[op[i]+1]^=1;
    	}
    	for(i=1;i<=n+1;i++)	if(vis[i])	w[m++]=i,vis[i]=0;
    	for(i=1;i<=L;i++)	v[i]=rd();
    	sort(w,w+m);
    	for(i=0;i<m;i++)	Log[1<<i]=i;
    	for(i=0;i<m;i++)
    	{
    		memset(dis,0x3f,sizeof(dis));
    		q.push(w[i]),dis[w[i]]=0;
    		while(!q.empty())
    		{
    			u=q.front(),q.pop();
    			for(j=1;j<=L;j++)
    			{
    				if(u+v[j]<=n+1&&dis[u+v[j]]==0x3f3f3f3f)	dis[u+v[j]]=dis[u]+1,q.push(u+v[j]);
    				if(u-v[j]>=1&&dis[u-v[j]]==0x3f3f3f3f)	dis[u-v[j]]=dis[u]+1,q.push(u-v[j]);
    			}
    		}
    		for(j=0;j<m;j++)	if(i!=j)	f[i][j]=dis[w[j]];
    	}
    	g[0]=0;
    	for(i=1;i<(1<<m);i++)
    	{
    		a=Log[i&-i];
    		for(j=a+1;j<m;j++)	if((i>>j)&1)	g[i]=min(g[i],g[i^(1<<j)^(1<<a)]+f[j][a]);
    	}
    	printf("%d
    ",(g[(1<<m)-1]==0x3f3f3f3f)?-1:g[(1<<m)-1]);
    }
    int main()
    {
    	int T=rd();
    	while(T--)	work();
    	return 0;
    }//2 10 8 2 1 2 3 5 6 7 8 9 3 5 3 2 1 1 2 3
    //1 10 3 2 1 1 10 10 8
  • 相关阅读:
    Unity3d vector3.forward和transform.forward的区别!
    UGUI实现摇杆
    UGUI实现拼图游戏
    Unity3d打包发布Android程序
    兼容PC和手机触摸代码
    unity3d中Transform组件变量详解
    运算符重载
    扩展方法
    string.Format格式化输出
    网络编程之Socket的TCP协议实现客户端与客户端之间的通信
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7965415.html
Copyright © 2011-2022 走看看