[恢复状态] 79D Password
题意:
给你一个全白的数组
你每次可以对连续ai个格子翻转,使得最终结果中k个格子是白色的(k<=10且给定哪些格子是白的)
求最小要几步
大概这题算法需要的比较多..
首先,我们看"连续翻转"一条
连续翻转一堆,不如"差分"
"差分" 即每次是否变化,如果变化了则记录"变化",没变化记录"没变",这样一个操作等于在两个点而不是一长条线上打tag了
所以..差分后..我们可以对这个玩意儿建图建边..
x到x+ai建边
所以图建好了,我们看某个点到另一个点的最短路
经过一条最短路,我们等于通过这一系列操作消去反应掉了一组
我们只要消掉所有组即可..这时候就可以写的2^(2k)的装压dp来处理这事儿了..
代码:
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<string>
#include<math.h>
#include<time.h>
#include<vector>
#include<bitset>
#include<memory>
#include<utility>
#include<fstream>
#include<stdio.h>
#include<sstream>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[15];
int b[10005];
int dist[10005];
int c[25][25];
int dp[1<<20];
map<int,int> ma;
struct edge
{
int y;
edge * next;
};
edge * li[10005];
edge * new_edge()
{
static edge a[2000005];
static int top=0;
return &a[top++];
}
void inserts(int x,int y)
{
edge * t=new_edge();
t->y=y;
t->next=li[x];
li[x]=t;
}
void insert_edge(int x,int y)
{
inserts(x,y);
inserts(y,x);
}
void bfs(int x)
{
static int que[10005];
int front=0,rail=1;
que[0]=x;
dist[x]=0;
for (;front<rail;front++)
{
int now=que[front];
edge * t;
for (t=li[now];t!=0;t=t->next)
{
if (dist[t->y]==-1)
{
dist[t->y]=dist[now]+1;
que[rail++]=t->y;
}
}
}
}
int main()
{
#ifdef absi2011
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
int n,k,l;
scanf("%d%d%d",&n,&k,&l);
n++;
int i;
for (i=0;i<k;i++)
{
scanf("%d",&a[i]);
b[a[i]-1]^=1;
b[a[i]]^=1;
}
for (i=0;i<l;i++)
{
int x;
scanf("%d",&x);
int j;
for (j=0;j<n-x;j++)
{
insert_edge(j,j+x);
}
}
int sum=0;
for (i=0;i<n;i++)
{
if (b[i])
{
ma[i]=sum++;
memset(dist,-1,sizeof(dist));
bfs(i);
int j;
for (j=0;j<i;j++)
{
if (b[j])
{
c[ma[i]][ma[j]]=dist[j];
c[ma[j]][ma[i]]=dist[j];
}
}
}
}
for (i=0;i<(1<<sum);i++)
{
dp[i]=1<<30;
}
dp[0]=0;
for (i=0;i<(1<<sum);i++)
{
int j,k;
for (j=0;j<sum;j++)
{
if (((1<<j)&i)) continue;
for (k=j+1;k<sum;k++)
{
if (((1<<k)&i)) continue;
if (c[j][k]==-1) continue;
dp[i^(1<<j)^(1<<k)]=min(dp[i^(1<<j)^(1<<k)],dp[i]+c[j][k]);
}
}
}
if (dp[(1<<sum)-1]>=(1<<29))
{
printf("-1\n");
}
else
{
printf("%d\n",dp[(1<<sum)-1]);
}
return 0;
}
评论 (0)