P2622 关灯问题II (状态压缩,最短路)

题目链接


Solution

这道题算是很经典的状压问题了,好题.
考虑到 \(n\) 的范围仅为 \(10\) , 那么也就是说所有状态压起来也只有 \(1024\) 种情况.
然后我们发现 \(m\) 居然小于 \(100\) .
于是可以 \(O(nm)\) 处理出每一种情况可以到达的结果.
然后形成一个有向图,然后直接跑 \(SPFA\) 就好了.

Code

/*  
Problem: P2622
Time : Day -96
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=1008;
struct sj{
    int to;
    int next;
}a[maxn*maxn*2];
int head[maxn],size;
int opt[maxn][20],n,m;

int read()
{
    char ch=getchar(); int f=1,w=0;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){w=w*10+ch-'0';ch=getchar();}
    return f*w;
}

void add(int x,int y)
{
    a[++size].to=y;
    a[size].next=head[x];
    head[x]=size;
}
int c[20]={0},b[20]={0};
void pre()
{
    int tot=(1<<n)-1;
    for(int i=tot;i>0;i--)
    {
        for(int j=n-1;j>=0;j--)
        c[j]=(i>>j)&1;
        for(int k=1;k<=m;k++)
        {
            for(int j=n-1;j>=0;j--)
            {
                if(opt[k][j]==1&&c[j]==1)
                b[j]=0;
                else if(opt[k][j]==-1&&c[j]==0)
                b[j]=1;
                else b[j]=c[j];
            }
            int fuck=0;
            for(int j=n;j>=0;j--)
            fuck=fuck*2+b[j];
            add(i,fuck);
        }
    }
}

queue<int>q;
int dis[maxn],v[maxn];
void spfa()
{
    int s=(1<<n)-1;
    memset(dis,127,sizeof(dis));
    dis[s]=0;
    q.push(s);
    v[s]=1;
    while(q.empty()!=1)
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=a[i].next)
        {
            int tt=a[i].to;
            if(dis[x]+1<dis[tt])
            {
                if(!v[tt])
                q.push(tt),
                v[tt]=1;
                dis[tt]=dis[x]+1;
            }
        }
    }
}

int main()
{
    n=read();
    m=read();
    for(int i=1;i<=m;i++)
    for(int j=0;j<n;j++)
    opt[i][j]=read();
    pre();
    spfa();
    if(dis[0]<123456)
    cout<<dis[0]<<endl;
    else
    cout<<"-1"<<endl;
}

猜你喜欢

转载自www.cnblogs.com/Kv-Stalin/p/9432889.html