# "COCI 2009" POSLOZI - problem solving

• preface

This data is a little water (?).

• General idea of the topic

Give an arrangement with a length of \ (N \) \ ((1\le N\le 12) \). There are \ (M \) allowed modification methods \ ((1\le M\le \frac{N\times (N-1)}{2}) \) to ensure that the modification methods are not repeated. Each method is represented by \ (L,R \), which means that you can exchange the number with the subscript \ (L \) with the number with the subscript \ (R \).

You can modify the arrangement several times. Please give a modification scheme to change the original arrangement to \ (1,2,3,\ldots,N \). If there are multiple schemes, the scheme with the least modification times will be output. If there are multiple schemes, output any group.

• analysis

Direct IDA * will be lost by some carefully constructed data cards. Although this problem does not exist, we try to change the search method.

It is found that each operation is equivalent to exchanging two adjacent points.

Considering greed, if a point \ (i \) has reached its place, we greedily hope that it is not moving and mark it.

If the \ (i \) point is fixed, it means that other points cannot pass through this point when moving. However, this may lead to the situation that the result has no solution or the result is not optimal.

This means that several other points must be fixed before fixing the \ (i \) point.

Therefore, we consider the fixed order of each point, and let each point go where it should go in this order. It's obviously the shortest run here.

The upper limit is \ (12! \), but we can maintain whether there is a solution while running. We can prune vigorously.

Then add an IDA * and run fast.

It should be noted that multiple shortest paths may occur during the movement of each point. At this time, the first shortest path can be run first each time.

Simply prove that for paths \ (x \) to \ (y \), if there are multiple shortest paths, the first path is preferred. However, there must be an arrangement order so that a point on the first path is marked in advance, so that the first path cannot go. According to the previous priority, that arrangement will run the second shortest circuit at this time.

The third shortest circuit or above is the same.

But the constant of this method is a little large. You need to turn on O2 here to pass.

• code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
const int N=15*15*15,M=15*15*15;
const int inf=1e9;
struct node{
int x,y;
}b[M];
struct edge{
int v,nx;
int id;
}e[M];
int n,m,ne,f[N],a[N],p[N],d[N],lst[N],nxt[N],iid[N];
int ansn,tot,ans[M],t[M],dis[16][16];
bool vis[N];
queue<int> q;
int solve(int s,int t)
{
for(int i=1;i<=n;i++)d[i]=inf,lst[i]=0;
while(!q.empty())q.pop();
d[s]=0;q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=f[u];i;i=e[i].nx)
{
int v=e[i].v;
if(d[v]!=inf)continue;
if(vis[v])continue;
d[v]=d[u]+1;
lst[v]=u;
iid[v]=e[i].id;
q.push(v);
}
}
return d[t];
}
void getans(int res)
{
if(res>=ansn)return;
ansn=res;
for(int i=1;i<=res;i++)
ans[i]=t[i];
}
int geth()
{
int res=0;
for(int i=1;i<=n;i++)
res+=dis[i][p[i]];
return res;
}
void dfs(int x,int res,int deep)
{
if(x==n+1){getans(res);return;}
int h=geth();
if(res>=deep)
{
if(h==0){getans(res);return;}
return;
}
if(h/2+res>=ansn)return;
if(res>=ansn)return;
for(int i=1;i<=n;i++)
{
if(vis[i])continue;
int cnt=solve(i,p[i]);
if(cnt==inf)continue;
vis[i]=1;
for(int u=p[i];u!=i&&lst[u]!=0;u=lst[u])
{
swap(p[a[u]],p[a[lst[u]]]);swap(a[u],a[lst[u]]);
t[++tot]=iid[u];
}
dfs(x+1,tot,deep);
vis[i]=0;
solve(a[i],i);
while(tot>res)
{
swap(p[a[b[t[tot]].x]],p[a[b[t[tot]].y]]);
swap(a[b[t[tot]].x],a[b[t[tot]].y]);
tot--;
}
}
}
{
e[++ne].v=v;
e[ne].nx=f[u];
f[u]=ne;
e[ne].id=w;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
p[a[i]]=i;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)dis[i][j]=inf;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&b[i].x,&b[i].y);
if(b[i].x==b[i].y)continue;
dis[b[i].x][b[i].y]=dis[b[i].y][b[i].x]=1;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
int deep=0;
while(deep<=n*n)
{
ansn=inf;
dfs(1,0,deep);
if(ansn!=inf)break;
deep++;
}
printf("%d\n",ansn);
for(int i=1;i<=ansn;i++)
printf("%d\n",ans[i]);
return 0;
}


Posted on Fri, 05 Nov 2021 14:20:30 -0400 by kuliksco