3149: [Ctsc2013]复原
Time Limit: 10 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 95 Solved: 44
[Submit][Status][Discuss]
Description
在几何课上,老师画了一个圆,圆上有很多条弦,这些弦两两不重合,但是 有些是相交的。你本想把图临摹下来回家好好研究,可惜下课后,图被值日生 擦掉了。幸运的是,你准确地记录了弦的数量和弦的相交情况。
现在,你想尽量复原这张图。同时你还想知道,最多能选出多少条弦,使得 选出来的弦两两不相交。
Input
第一行包含2个正整数n,m,分别表示弦的条数以及相交弦的对数,所有的弦从1至n编号。接下来 m行每行两个正整数a,b,表示第a条弦与第b条弦相交。
Output
输出分为两行。
第一行输出2n个正整数,按逆时针方向给出满足题意的圆上每条弦的两个
端点的相对顺序,其中第i条弦的两个端点均用数字i来表示。
第二行输出1个正整数,表示最多能选多少条两两不相交的弦。
Sample Input
5 6
1 2
1 3
2 3
2 4
3 5
4 5
1 2
1 3
2 3
2 4
3 5
4 5
Sample Output
1 2 3 1 4 2 5 4 3 5
2
2
HINT
1<=N<=20 1<=M<=40
Source
//表示只会10分暴力 //对大神的位运算优化膜拜。 #include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N=25; const int M=1.5e6+5; int n,m,len,cnt,bin[N],lg[M],f[M],q[N],mp[N],pth[N<<1],ans[N<<1]; bool a[N][N],vis[N];int sum,end; inline void Max(int &x,int y){if(x<y) x=y;} bool dfs(int k,int goal){ if(k>goal) return 1; len++; for(int i=len;i;i--) pth[i]=pth[i-1]; for(int i=1;i<=len;i++){ pth[i]=k;len++; for(int j=len;j>i+1;j--) pth[j]=pth[j-1]; for(int j=i+1,s=0;j<=len;j++){ pth[j]=k; if(!(s^mp[k]) && dfs(k+1,goal)) return 1; pth[j]=pth[j+1]; s^=bin[pth[j]-1]; } len--;pth[i]=pth[i+1]; } len--; return 0; } int bfs(int S){ int h=0,t=1;len=0;q[t]=S;vis[S]=1; while(h!=t){ int x=q[++h]; for(int i=1;i<=n;i++){ if(!vis[i] && a[x][i]){ vis[i]=1; q[++t]=i; } } } for(int j=1;j<=t;j++){ mp[j]=0; for(int k=1;k<j;k++){ if(a[q[j]][q[k]]) mp[j]|=bin[k-1]; } } return t; } void work(){ for(int i=1;i<=len;i++) ans[++cnt]=q[pth[i]]; for(int i=1;i<=end;i++){ mp[i]=bin[i-1]; for(int j=1;j<=end;j++){ if(a[q[i]][q[j]]){ mp[i]|=bin[j-1]; } } } int mx=0,tot=bin[end]-1; memset(f,0,sizeof f); for(int j=tot,x;j;j--){ mx=max(mx,f[j]); for(int k=j;k;k^=x){ x=k&-k; Max(f[j&(tot^mp[lg[x]+1])],f[j]+1); } } sum+=max(mx,f[0]); } int main(){ scanf("%d%d",&n,&m); for(int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),a[x][y]=a[y][x]=1; for(int i=0;i<=n;i++) bin[i]=1<<i; for(int i=2;i<=bin[n];i++) lg[i]=lg[i>>1]+1; for(int i=1;i<=n;i++) if(!vis[i]){ end=bfs(i); dfs(1,end); work(); } for(int i=1;i<=cnt;i++) printf("%d%c",ans[i],(i<cnt)?' ':'\n'); printf("%d\n",sum); return 0; }