WC 2008 password

很好的一道題。。。抽出模型是這題關鍵的一步。。。其實可以作爲傳統類題的。。。但是如果有任何關於連通性的描述就會徹底破壞這題的價值。。。所以它就成了提交答案式。。。

我只做了歐拉回路的測試點。。。因爲木有時間了。。。構圖很簡單。。。將入度大於出度的作爲A類,入度小於出度的爲B類。。。源向A連邊,流量爲in-out,B向匯連邊,流量爲out-in。。。中間的爲oo,費用分情況討論。。。(abc)->(bcd)爲1,(abc)->(cde)爲2,(abc)->(def)爲3。。。

最後輸出方案時注意,由於你求的是迴路。。。那麼首尾點一定是同一個點。。。對於倒數第二個點。。。有可能會與第一個點有重複的地方,也要去掉。。。

Code:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
const int source=1000,sink=1001,maxm=2020055;
typedef long long ll;
int e=1,ed=1,top=0,tail=0,m=0,len=0,tot=0,totlen=0;
int head[1005],now[1005],link[maxm],next[maxm],cost[maxm],dis[1005],sta[maxm*3],pre[1005],list[maxm],ans[maxm];
ll w[maxm],d1[1005],d2[1005],g[1005][1005];
bool vis[1005];
bool spfa()
{
  top=0;
  sta[tail=1]=source;
  memset(vis,0,sizeof(vis));
  memset(dis,65,sizeof(dis));
  memset(pre,0,sizeof(pre));
  int oo=dis[0]-1,x=0,y=0,ne=0;
  dis[source]=0;
  vis[source]=1;
  while (top<tail)
    {
      x=sta[++top];
      for (ne=head[x],y=link[ne];ne;ne=next[ne],y=link[ne])
	if (w[ne])
	  if (dis[x]+cost[ne]<dis[y])
	    {
	      dis[y]=dis[x]+cost[ne];
	      if (!vis[y])
		sta[++tail]=y,vis[y]=1;
	      pre[y]=x;
	      now[y]=ne;
	    }
      vis[x]=0;
    }
  if (dis[sink]<oo) return 1;
  return 0;
}
void add(int u,int v,ll tmpw,int tmpc)
{
  next[++e]=head[u];
  head[u]=e;
  link[e]=v;
  w[e]=tmpw;
  cost[e]=tmpc;
  next[++e]=head[v];
  head[v]=e;
  link[e]=u;
  w[e]=0;
  cost[e]=-tmpc;
}
int get()
{
  int nop=sink;
  ll flows=2000000000;
  for (;nop!=source;nop=pre[nop])
    if (flows>w[now[nop]])
      flows=w[now[nop]];
  for (nop=sink;nop!=source;nop=pre[nop])
    w[now[nop]]-=flows,w[now[nop]^1]+=flows;
  return flows*dis[sink];
}
void dfs(int i)
{
  for (int j=0;j<=999;j++)
    if (g[i][j])
      {
	g[i][j]--;
	dfs(j);
      }
  list[++len]=i;
}
int main(int argc,char *argv[])
{
  char inname[200],outname[200];
  memset(inname,0,sizeof(inname));
  memset(outname,0,sizeof(outname));
  sprintf(inname,"password%s.in",argv[1]);
  sprintf(outname,"password%s.out",argv[1]);
  freopen(inname,"r",stdin);
  freopen(outname,"w",stdout);
  scanf("%d",&m);
  int i=0,j=0;
  int ch=0,pres=0,nows=0;
  for (i=1;i<=m;i++)
    {
      scanf("%d",&ch);
      pres=ch/10;
      nows=ch%1000;
      if (!g[pres][nows])
	{
	  g[pres][nows]=1;
	  d1[pres]++;
	  d2[nows]++;
	  totlen++;
	}
    }
  int tmpc=0;
  for (i=0;i<=999;i++)
    if (d1[i]>d2[i])
      for (j=0;j<=999;j++)
	if (d2[j]>d1[j])
	  {
	    if ((j%100)==(i/10))
	      tmpc=1;
	    else
	      if ((j%10)==(i/100))
		tmpc=2;
	      else
		tmpc=3;
	    add(j,i,2000000000,tmpc);
	  }
  for (i=0;i<=999;i++)
    if (d2[i]>d1[i])
      add(source,i,d2[i]-d1[i],0);
    else
      if (d1[i]>d2[i])
	add(i,sink,d1[i]-d2[i],0);
  while (spfa()) totlen+=get();
  int ne=0;
  for (i=0;i<=999;i++)
    if (d2[i]>d1[i])
      for (ne=head[i];ne;ne=next[ne])
	if (!(ne&1))
	  g[i][link[ne]]+=w[ne^1];
  len=0;
  for (i=0;i<=999;i++)
    if (d1[i]+d2[i]>0)
      {
	dfs(i);
	break;
      }
  len--;
  tot=3;
  ans[1]=list[len]/100;
  ans[2]=(list[len]/10)%10;
  ans[3]=list[len]%10;
  for (i=len-1;i>=1;i--)
    { 
      if ((list[i+1]%100)==(list[i]/10))
	{
	  tot++;
	  ans[tot]=list[i]%10;
	}
      else
	if ((list[i+1]%10)==(list[i]/100))
	  {
	    tot+=2;
	    ans[tot-1]=(list[i]/10)%10;
	    ans[tot]=list[i]%10;
	  }
	else
	  {
	    tot+=3;
	    ans[tot-2]=list[i]/100;
	    ans[tot-1]=(list[i]/10)%10;
	    ans[tot]=list[i]%10;
	  }
    }
  printf("%d\n",totlen);
  for (i=1;i<=totlen;i++)
    printf("%d",ans[i]);
  return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章