题目描述
样例呢?
我也不知道
task1/2
直接暴力就行了吧。。。
task3
因为m<=15,所以考虑状压dp
设f[t][i][s][0/1/2]表示当前跳跃t次,在第i个点,且走过的边状态为s(状压)时上一个可能的状态
有一个显然的性质,跳跃的次数肯定不会大于m
因为最坏的情况是每一条边跳到其中一个端点,然后再走一次
于是随便转移,时间复杂度
O(m2n2m)
O
(
m
2
n
2
m
)
(最坏情况)
最后反着输出方案
code
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
using namespace std;
int a[200002][2];
int ls[100001];
int f[16][32768][16][3];
bool bz[16][32768][16];
int p[16]={0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384};
int n,m,i,j,k,l,x,y,len,L;
void New(int x,int y)
{
len++;
a[len][0]=y;
a[len][1]=ls[x];
ls[x]=len;
}
void dg(int x,int y,int z)
{
if (!bz[f[x][y][z][0]][f[x][y][z][1]][f[x][y][z][2]])
{
printf("%d\n",z);
return;
}
dg(f[x][y][z][0],f[x][y][z][1],f[x][y][z][2]);
printf("%d %d\n",x-f[x][y][z][0],z);
}
int main()
{
freopen("miner.in","r",stdin);
freopen("miner.out","w",stdout);
scanf("%d%d",&n,&m);
len=1;
fo(i,1,m)
{
scanf("%d%d",&x,&y);
New(x,y);
New(y,x);
}
if (n<=15 && m<=15)
{
L=p[m]*2-1;
fo(i,1,n)
bz[0][0][i]=1;
fo(i,0,m)
{
fo(j,0,L-1)
{
fo(k,1,n)
if (bz[i][j][k])
{
for (l=ls[k]; l; l=a[l][1])
if (!(j&p[l>>1]))
{
int J=j|p[l>>1];
if (!bz[i][J][a[l][0]])
{
bz[i][J][a[l][0]]=1;
f[i][J][a[l][0]][0]=i;
f[i][J][a[l][0]][1]=j;
f[i][J][a[l][0]][2]=k;
}
}
if (i<m)
{
fo(l,1,n)
if (!bz[i+1][j][l])
{
bz[i+1][j][l]=1;
f[i+1][j][l][0]=i;
f[i+1][j][l][1]=j;
f[i+1][j][l][2]=k;
}
}
}
}
}
fo(i,0,m)
{
fo(j,1,n)
if (bz[i][L][j])
{
printf("%d\n",i);
dg(i,L,j);
return 0;
}
}
return 0;
}
printf("0\n");//text5
fclose(stdin);
fclose(stdout);
return 0;
}
task4
不知道
task5
因为且
所以
printf("0\n");
就有6分了(逃
咳咳
因为没有跳跃操作,所以直接在连通块里找欧拉路径(后来才发现其实不是回路)
欧拉回路/路径
来自百度
如果图G中的一个路径包括每个边恰好一次,则该路径称为欧拉路径(Euler path)。
如果一个回路是欧拉路径,则称为欧拉回路(Euler circuit)。
求欧拉回路有一种十分方便快捷的方法——Hierholzer算法
Hierholzer算法同样资瓷求欧拉路径(前提是要找一个合法的出发点)
设图中度数为奇数的点个数为x个,则
①x=0 任意点都可以
②x=2 在两个奇点中二选一
③x>2 无解
考虑最暴力的方法,每次不断dfs找经过所有边的路径
但是这样效率很低,因为可能会出现这样的情况:
从点1出发,沿着1-2-5-6-3-2的顺序去走
如果用普通的dfs,则需要退到5处,再走5-1-4-6-3-2,这样效率很低
但欧拉回路(好像)有个神奇的性质,就是当你选对一个点后,只要不走到死路提前去世,随便xjb走都可以走出一条路来
所以观察上面的路径,发现其实5-6-3-2可以放到后面去走,先走5-1-4-5
所以程序流程是:
对于当前点u
for (u,v)∈[E]
删除 (u,v)
删除 (v,u)
递归v
把u加入答案集合
最后倒叙输出答案集合
思想和上面一样,如果走到死胡同就先放着,走完其它的边再走
代码比较简洁就不放了
于是这样就可以过text5了
task6
因为原图可能不连通,所以考虑分开一个个连通块来做
显然做完一个跳到另一个去做才是最优的
所以问题就变成处理每一个连通块
然而连通块内可能不能直接构成一个欧拉路径,必须要用卢本伟修改器来跳
有一个性质,一个无向图内奇数度数的点的个数x一定为偶数
采用反证法反正就是对的
如果x为奇数,则x*奇数度数+y*偶数度数=奇数
但在无向图中,每加一条边总度数就会+2
所以总度数一定为偶数,x必为偶数
因为x可能大于2,所以考虑用一条边把两个奇数度数的点连起来,这样等于做了一次1操作
那么就用最少的边把每个连通块变成x=0 or 2
之后随便搞搞欧拉回路久行了
(要开人工栈)
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
using namespace std;
int A[300011];
int a[300011][3];
int ls[100001];
int c[100001];
int b[100001];
bool bz[100001];
int g[100001];
int d[300001];
int D[300001];
bool Bz[300001];
int F[100001];
int fa[100001];
int n,m,i,j,k,l,x,y,len,ans,s,L,Len,II,next,t;
int T[300001];
int I[300001];
void New(int x,int y)
{
len++;
A[len]=x;
a[len][0]=y;
a[len][1]=ls[x];
a[ls[x]][2]=len;
ls[x]=len;
}
int gf(int t)
{
if (fa[t]==t)
return t;
fa[t]=gf(fa[t]);
return fa[t];
}
void del(int t)
{
int pre=a[t][1],suc=a[t][2];
Bz[t]=1;
if (pre)
a[pre][2]=suc;
if (suc)
a[suc][1]=pre;
if (ls[A[t]]==t)
ls[A[t]]=pre;
}
void dfs(int t)
{
int i;
F[t]=II;
if (b[t]&1)
{
c[++L]=t;
s++;
}
bz[t]=1;
for (i=ls[t]; i; i=a[i][1])
if (!bz[a[i][0]])
dfs(a[i][0]);
}
void Dfs(int tt)
{
t=1;
T[1]=tt;
while (t)
{
if (I[T[t]])
{
if (!Bz[I[T[t]]])
{
next=a[I[T[t]]][0];
del(I[T[t]]);
del(I[T[t]]^1);
T[++t]=next;
}
else
I[T[t]]=a[I[T[t]]][1];
}
else
{
d[++Len]=T[t];
while (g[T[t]])
d[++Len]=T[t],g[T[t]]--;
t--;
I[T[t]]=a[I[T[t]]][1];
}
}
}
int main()
{
freopen("miner.in","r",stdin);
freopen("miner.out","w",stdout);
len=1;
scanf("%d%d",&n,&m);
fo(i,1,m)
{
scanf("%d%d",&x,&y);
if (x==y)
g[x]++;
else
New(x,y),New(y,x);
b[x]++;
b[y]++;
}
fo(i,1,n)
I[i]=ls[i];
fo(i,1,n) fa[i]=i;
fo(i,1,n)
if (!bz[i] && b[i])
{
II=i;
L=0;
s=0;
dfs(i);
s>>=1;
if (s)
ans+=(s-1);
ans++;
for (j=3; j<=L; j+=2)
{
New(c[j],c[j+1]);
New(c[j+1],c[j]);
I[c[j]]=ls[c[j]];
I[c[j+1]]=ls[c[j+1]];
fa[gf(c[j])]=gf(c[j+1]);
}
k=Len+1;
if (L)
{
Dfs(c[1]);
fo(j,k+1,Len)
if (d[j-1]!=d[j] && gf(d[j-1])==gf(d[j]))
{
fa[d[j-1]]=d[j-1];
fa[d[j]]=d[j];
D[j]=1;
}
}
else
Dfs(i);
}
printf("%d\n",ans-1);
printf("%d\n",d[1]);
fo(i,2,Len)
printf("%d %d\n",max(D[i],(F[d[i]]!=F[d[i-1]])),d[i]);
fclose(stdin);
fclose(stdout);
return 0;
}