WC 2009 opt 优化设计

本文探讨了一种特定的SAT问题,通过分析不同测试点的特点,采用枚举、2-SAT算法、状态压缩DP、二分图匹配及随机模拟退火等方法解决。针对各测试点特性,提供详细的算法实现思路及代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个题其实就是sat问题,是个NPC,所以做这题基本上是休闲。

但其实分析数据可以发现每个数据都是有目的,并不完全是混乱的boolean表达式。

首先对于第一、二两个点数据其实质就是枚举,让我想到了NOIP04年的等价表达式。。。囧。。。

point 3、4、5、6就是2-sat问题,本弱菜写2-sat的题目不多,基本上中规中矩除读入140几行。构图什么的几乎木有,裸的2-sat问题,345都可以满足,6号点有三个无法满足,不知是哪几个,所以就为了方便删了最后三个,好像碰上了的说。。。

如果不会2-sat自行百度“赵爽 2-sat”,写得很详细。由于这东西并不是热点,考不考是个未知。

7号点是状态压缩么,将m个表达式按照读入的第一个变元序号排序,f[i][s]表示以i个式子变元为首的连续11个变元赋值为s的状态下前i个式子最多满足多少个,

然后就是环的处理,以跨过n号变元的式子为头,再做一遍DP,与之前的取最优值就可以了。

8号点二分图匹配,看一下数据就知道,对于每个式子,将差值为1的点捆绑为一点,以变元可满足式子的赋值作为压缩的状态赋为边的属性,匈牙利的时候记录选的边是哪条

9号点完全就是sat问题了,除了随机模拟退火外没有好的算法。

10号点是个构造,很容易的,但是DP解法就不知如何想了。

Code:point 3、4、5、6

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
typedef int arr2[6000005];
typedef int arr[400005];
arr2 foll,link,poin,next,sta;
arr head,last,tops,anti,vis,low,rea,f,degree,bro,son,color,que;
int n=0,m=0,e=1,time=0,top=0,tail=0,hea=0;
bool view[400005];
inline int min(int q,int p)
{
  return q<p?q:p;
}
void add(int u,int v)
{
  next[++e]=head[u];
  head[u]=e;
  link[e]=v;
  if (next[e]==0) last[u]=e;
}
void addoth(int u,int v)
{
  foll[++e]=tops[u];
  tops[u]=e;
  poin[e]=v;
}
void init34()
{
  char ch=0;
  int i=0,u=0,v=0;
  for (i=1;i<=m;i++)
    {
      scanf("%c",&ch);
      if (ch=='~')
	{
	  scanf("x%d",&u);
	  u=anti[u];
	  scanf("|%c",&ch);
	  if (ch=='~')
	    {
	      scanf("x%d\n",&v);
	      v=anti[v];
	    }
	  else
	    scanf("%d\n",&v);
	}
      else
	{
	  scanf("%d|",&u);
	  scanf("%c",&ch);
	  if (ch=='~')
	    {
	      scanf("x%d\n",&v);
	      v=anti[v];
	    }
	  else
	    scanf("%d\n",&v);
	}
      add(anti[v],u);
      add(anti[u],v);
    }
}
void init5()
{
  int i=0,j=0,u=0;
  char ch=0;
  if (m==33333) m-=3;
  for (i=1;i<=m;i++)
    {
      hea=0;
      scanf("%c",&ch);
      for (scanf("%c",&ch);ch!=')';scanf("%c",&ch))
	{
	  if (ch=='&') scanf("%c",&ch);
	  if (ch=='~')
	    {
	      scanf("x%d",&u);
	      u=anti[u];
	    }
	  else
	    scanf("%d",&u);
	  que[++hea]=u;
	}
      scanf("|%c",&ch);
      for (scanf("%c",&ch);ch!=')';scanf("%c",&ch))
	{
	  if (ch=='&') scanf("%c",&ch);
	  if (ch=='~')
	    {
	      scanf("x%d",&u);
	      u=anti[u];
	    }
	  else
	    scanf("%d",&u);
	  for (j=1;j<=hea;j++)
	    {
	      add(anti[que[j]],u);
	      add(anti[u],que[j]);
	    }
	}
      scanf("%c",&ch);
    }
}
void dfs(int s)
{
  vis[s]=1;
  rea[s]=low[s]=++time;
  sta[++top]=s;
  int ne=0,y=0;
  for (ne=head[s];ne;ne=next[ne])
    {
      y=link[ne];
      if (vis[y]==0) dfs(y);
      if (vis[y]==1) low[s]=min(low[s],low[y]);
    }
  if (rea[s]==low[s])
    {
      for(;sta[top+1]!=s;top--)
	{
	  y=sta[top];
	  f[y]=s;
	  vis[y]=2;
	  if (y==s) break;
	  bro[y]=son[s];
	  son[s]=y;
	}
      top--;
    }
}
void edgeanti(int s)
{
  int ne=0,y=0;
  view[s]=1;
  ++time;
  for (ne=head[s],y=f[link[ne]];ne;ne=next[ne],y=f[link[ne]])
    if (vis[y]!=time && y!=s)
      {
	vis[y]=time;
	addoth(y,s);
	++degree[s];
      }
}
void bfs(int s)
{
  color[s]=3;
  int ne=0,y=0;
  for (ne=tops[s],y=poin[ne];ne;ne=foll[ne],y=poin[ne])
    if (!color[y]) bfs(y);
}
void topsort()
{
  int i=0;
  top=0,tail=0;
  for (i=1;i<=2*n;i++)
    if (view[f[i]])
      {
	view[f[i]]=0;
	if (degree[f[i]]==0)
	  sta[++tail]=f[i];
      }
  int ne=0,y=0,x=0;
  while (top<tail)
    {
      x=sta[++top];
      for (ne=tops[x],y=poin[ne];ne;ne=foll[ne],y=poin[ne])
	{
	  degree[y]--;
	  if (degree[y]==0)
	    sta[++tail]=y;
	}
    }
  for (i=1;i<=tail;i++)
    if (!color[x = sta[i]])
      {
	color[x]=2;
	if (!color[y = f[anti[x]]]) bfs(y);
	for (ne=son[x],y=f[anti[ne]];ne;ne=bro[ne],y=f[anti[ne]])
	  {
	    if (!color[y]) bfs(y);
	  }
      }
}
int main(int argc,char* argv[])
{
  char inname[200],outname[200];
  memset(inname,0,sizeof(inname));
  memset(outname,0,sizeof(outname));
  int i=0;
  sprintf(inname,"opt%s.in",argv[1]);
  sprintf(outname,"opt%s.out",argv[1]);
  freopen(inname,"r",stdin);
  freopen(outname,"w",stdout);
  scanf("%d%d\n",&n,&m);
  for (i=1;i<=n;i++)
    {
      anti[i]=i+n;
      anti[i+n]=i;
    }
  if (inname[3]=='3'||inname[3]=='4')
    init34();
  else
    init5();
  for (i=1;i<=2*n;i++)
    if (!vis[i])
      dfs(i);
  memset(vis,0,sizeof(vis));
  int ne=0;
  for (i=1;i<=2*n;i++)
    if (!vis[f[i]])
      {
	vis[f[i]]=1;
	ne=son[f[i]];
	while (ne)
	  {
	    next[last[ne]]=head[f[i]];
	    head[f[i]]=head[ne];
	    head[ne]=0;
	    ne=bro[ne];
	  }
      }
  memset(vis,0,sizeof(vis));
  time=0;
  e=0;
  for (i=1;i<=2*n;i++)
    if (!view[f[i]])
      edgeanti(f[i]);
  topsort();
  for (i=1;i<=n;i++)
    if (color[f[i]]==2)
      printf("1\n");
    else
      printf("0\n");
  return 0;
}

Code point 7:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
struct fomula
{
  int sta,appear,posine;
  bool spe;
} fomu[505];
int n=0,m=0;
int f[505][2052],path[505][2052];
int code[105];
bool flag[505][2052];
int cmp(const void *p,const void *q)
{
  return (*(fomula*)p).sta-(*(fomula*)q).sta;
}
void init()
{
  int i=0,u=0,delta=0;
  char ch=0;
  for (i=1;i<=m;i++)
    {
      scanf("%c",&ch);
      if (ch=='~')
	{
	  scanf("x%d",&u);
	  fomu[i].appear=1;
	  fomu[i].posine=0;
	}
      else
	{
	  scanf("%d",&u);
	  fomu[i].appear=1;
	  fomu[i].posine=1;
	}
      fomu[i].sta=u;
      for (scanf("%c",&ch);ch!='\n';scanf("%c",&ch))
	{
	  if (ch=='&') scanf("%c",&ch);
	  if (ch=='~')
	    {
	      scanf("x%d",&u);
	      delta=u-fomu[i].sta;
	      if (delta<0)
		{
		  delta+=100;
		  fomu[i].spe=1;
		}
	      fomu[i].appear+=(1<<delta);
	    }
	  else
	    {
	      scanf("%d",&u);
	      delta=u-fomu[i].sta;
	      if (delta<0)
		{
		  delta+=100;
		  fomu[i].spe=1;
		}
	      fomu[i].appear+=(1<<delta);
	      fomu[i].posine+=(1<<delta);
	    }
	}
    }
}
bool infer(fomula a,int state)
{
  int i=0;
  for (i=0;i<=10;i++)
    {
      if (a.appear&1)
	if (a.posine&1)
	  {
	    if (!(state&1)) return 0;
	  }
	else
	  {
	    if (state&1) return 0;
	  }
      a.appear>>=1;
      a.posine>>=1;
      state>>=1;
    }
  return 1;
}
void dfs(int s,int state)
{
  int i=0,stmp=state;
  if (s==0) return;
  for (i=0;i<=10;i++)
    {
      code[i+fomu[s].sta]=stmp&1;
      stmp>>=1;
    }
  if (flag[s][state])
    dfs(s-1,path[s][state]);
}
bool infer(fomula a)
{
  int i=0;
  for (i=0;i<=10;i++)
    {
      if (a.appear&1)
	if (a.posine&1)
	  {
	    if (!code[i+a.sta]) return 0;
	  }
	else
	  {
	    if (code[i+a.sta]) return 0;
	  }
    }
  return 1;
}
int main()
{
  freopen("opt7.in","r",stdin);
  freopen("opt7.out","w",stdout);
  scanf("%d%d\n",&n,&m);
  init();
  qsort(fomu+1,m,sizeof(fomu[0]),cmp);
  fomu[0].sta=1;
  fomu[0].appear=(1<<11)-1;
  fomu[0].posine=(1<<11)-1;
  int state=0,i=0,now=0,nex=0,tmp=0,nstate=0,fixed=0,delta=0,rest=0;
  for (i=0;i<m && (!fomu[i].spe);i++)
    for (state=0;state<=(1<<11)-1;state++)
      {
	now=fomu[i].sta;
	nex=fomu[i+1].sta;
	delta=nex-now;
	fixed=state>>delta;
	if (!fomu[i].spe)
	  for (rest=0;rest<=(1<<delta)-1;rest++)
	    {
	      nstate=fixed+(rest<<(11-delta));
	      if (infer(fomu[i+1],nstate)) tmp=f[i][state]+1;
	      else tmp=f[i][state];
	      if (tmp>=f[i+1][nstate])
		{
		  path[i+1][nstate]=state;
		  f[i+1][nstate]=tmp;
		  flag[i+1][nstate]=1;
		}
	    }
	else
	  break;
      }
  int tend=i-1,stmp=0,anss=0,anst=0;
  delta=n-(fomu[tend].sta+10);
  if (delta<0) delta=0;
  for (nstate=0;nstate<=1<<delta;nstate++)
    {
      for (state=0;state<=(1<<11)-1;state++)
	{
	  memset(code,0,sizeof(code));
	  for (stmp=nstate,i=fomu[tend].sta+11;i<=n;i++,stmp>>=1)
	    code[i]=stmp&1;
	  dfs(tend,state);
	  for (i=tend+1;i<=m;i++)
	    if (infer(fomu[i]))
	      f[tend][state]++;
	  if (f[tend][state]>=f[tend][anss])
	    {
	      anss=state;
	      anst=nstate;
	    }
	}
    }
  memset(code,0,sizeof(code));
  for (stmp=anst,i=fomu[tend].sta+11;i<=n;i++,stmp>>=1)
    code[i]=stmp&1;
  dfs(tend,anss);
  for (i=1;i<=n;i++)
    printf("%d\n",code[i]);
  return 0;
}

Code point 8:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
int e=1,n=0,m=0,nodesnum=0,top=0,tail=0,hea=0,bot=0;
int point[10005],li[10005],f[10005],attr[20005],head[10005],next[20005],link[20005],mych[10005],sta[10005],que[10005];
bool vis[10005];
void add(int u,int v,int e)
{
  next[e]=head[u];
  head[u]=e;
  link[e]=v;
}
void init()
{
  int i=0,u=0,last=0,thead=0,lastlast=0;
  char ch=0;
  for (i=1;i<=m;i++)
    {
      last=-10;
      for (scanf("%c",&ch);ch!='\n';scanf("%c",&ch))
	{
	  if (ch=='&') scanf("%c",&ch);
	  if (ch=='~')
	    {
	      scanf("x%d",&u);
	      if (u-last>1)
		{
		  lastlast=thead;
		  thead=u;
		  if (point[thead]==0) point[thead]=++nodesnum;
		  ++e;
		}
	    }
	  else
	    {
	      scanf("%d",&u);
	      if (u-last>1)
		{
		  lastlast=thead;
		  thead=u;
		  if (point[thead]==0) point[thead]=++nodesnum;
		  ++e;
		}
	      attr[e]+=(1<<(u-thead));
	    }
	  f[u]=thead;
	  last=u;
	}
      add(point[lastlast],point[thead],e-1);
      add(point[thead],point[lastlast],e);
    }
}
bool find(int x)
{
  if (x==0) return 0;
  vis[x]=1;
  for (int ne=head[x],y=link[ne];ne;ne=next[ne],y=link[ne])
    {
      if (!vis[y])
	{
	  vis[y]=1;
	  if (li[y]==0 || find(li[y]))
	    {
	      li[y]=x;
	      mych[y]=ne^1;
	      mych[x]=ne;
	      return 1;
	    }
	}
    }
  return 0;
}
bool infer(int s)
{
  int nst=attr[mych[point[f[s]]]];
  int delta=s-f[s];
  return (nst>>delta)&1;
}
void bfs(int s)
{
  vis[s]=1;
  sta[++tail]=s;
  int ne=0,x=0,y=0;
  while (top<tail)
    {
      while (top<tail)
	{
	  x=sta[++top];
	  for (ne=head[x],y=link[ne];ne;ne=next[ne],y=link[ne])
	    if (!vis[y])
	      {
		vis[y]=1;
		que[++bot]=y;
	      }
	}
      while (hea<bot)
	{
	  x=que[++hea];
	  for (ne=head[x],y=link[ne];ne;ne=next[ne],y=link[ne])
	    if (!vis[y])
	      {
		vis[y]=1;
		sta[++tail]=y;
	      }
	}
    }
}
int main()
{
  freopen("opt8.in","r",stdin);
  freopen("opt8.out","w",stdout);
  scanf("%d%d\n",&n,&m);
  init();
  int i=0,delta=0,x=0,j=0;
  for (i=1;i<=nodesnum;i++)
    if (!vis[i])
      bfs(i);
  for (i=1;i<=tail;i++)
    {
      memset(vis,0,sizeof(vis));
      find(sta[i]);
    }
  for (i=1;i<=n;i++)
    if (infer(i))
      printf("1\n");
    else
      printf("0\n");
  return 0;
}


448 1 root S 1490m150.1 1 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 449 1 root S 1490m150.1 1 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 454 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 460 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 461 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 462 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 463 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 464 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 465 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 466 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 467 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 468 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 558 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 559 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 560 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 561 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 562 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 563 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 564 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 565 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 570 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 571 1 root S 1490m150.1 1 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 572 1 root S 1490m150.1 1 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 578 1 root S 1490m150.1 0 0.0 {esc_8218e_poll} /opt/nos/bin/hsl -d -n 请分析原因
最新发布
08-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值