鏈接:http://codeforces.com/contest/590/problem/E
題意:給出n(n<=750)個字符串,要求從中選出儘可能多的串,使得兩兩不是包含關係,並輸出方案。(串長不超過
用AC自動機處理包含關係之後,題目轉化爲求最長反鏈,並輸出方案。關於DAG的最長反鏈,可以參考這個,然而本題的難點在於輸出方案。結論是:最小點覆蓋的補集就是最長反鏈的方案。首先,由於最小點覆蓋的補集大小=最長反鏈的大小,因此,只要證明這個補集是一個反鏈即可。而這是顯然的,因爲假如這不是一個反鏈,必然存在一對u,v,滿足u,v不在點覆蓋中,但是u,v之間有邊,這就表明那並不是一個點覆蓋,產生矛盾。
值得注意的是原有向無環圖必須先求一邊傳遞閉包,否則上述並不成立。
因此,只需要輸出一種最小點覆蓋的方案即可。自己yy了一種求點覆蓋的方法:
1.先令左邊的匹配的點都是點覆蓋中的點
2.對於每個左邊的非匹配點,假如他連接着一條未被覆蓋的邊,那麼就把對應的右點置爲覆蓋點,同時,由於這個右點必然是一個匹配點,要將他匹配的點移出覆蓋點
3.由於被移除了覆蓋點,有些非匹配邊可能未被覆蓋到,因此這時候遞歸的進行2即可
#include<bits/stdc++.h>
using namespace std;
const int Maxn=10000009;
int n;
string ss[755];
int ch[Maxn][2];
int f[Maxn],last[Maxn];
int val[Maxn],id[755];
int cnt,tot;//zong jie dian,zong chuan
void insert(int idx,string &s)
{
int rt=0;
for(int i=0;i<s.size();i++)
{
int c=s[i]-'a';
if(!ch[rt][c]){ch[rt][c]=cnt++;}
rt=ch[rt][c];
}
if(!val[rt]){val[rt]=++tot;id[tot]=idx;}
}
bool G[755][755];
int linkl[755],linkr[755];
bool done[755],isl[755],isr[755];
bool dfs(int u)
{
//printf("u=%d\n",u);
for(int i=1;i<=tot;i++)
{
if(!G[u][i]||done[i])continue;
done[i]=1;
if(!linkr[i]||dfs(linkr[i]))
{
linkr[i]=u;
return 1;
}
}
return 0;
}
void getf()
{
queue<int>q;
f[0]=0;
for(int c=0;c<2;c++)
{
int u=ch[0][c];
if(u){f[u]=0;q.push(u);last[u]=0;}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int c=0;c<2;c++)
{
int u=ch[r][c];
if(!u)continue;
q.push(u);
int v=f[r];
while(v&&!ch[v][c])v=f[v];
f[u]=ch[v][c];
last[u]=val[f[u]]?f[u]:last[f[u]];
}
}
}
void dfs2(int u)
{
for(int i=1;i<=tot;i++)
{
if(!G[u][i])continue;
if(!isr[i])
{
isr[i]=1;
isl[linkr[i]]=0;
dfs2(linkr[i]);
}
}
}
int main()
{
scanf("%d",&n);
cnt=1;
for(int i=1;i<=n;i++)
{
cin>>ss[i];
insert(i,ss[i]);
}
getf();
for(int i=1;i<=tot;i++)
{
int now=0;
string &s=ss[id[i]];
for(int j=0;j<s.size();j++)
{
int c=s[j]-'a';
now=ch[now][c];
if(j!=s.size()-1&&val[now])
{
G[i][val[now]]=1;
continue;
}
if(val[last[now]])
{
G[i][val[last[now]]]=1;
}
}
}
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
for(int k=1;k<=tot;k++)
{
if(G[j][i]&&G[i][k])G[j][k]=1;
}
/*
for(int i=1;i<=tot;i++)
{
for(int j=1;j<=tot;j++)
printf("%d ",G[i][j]);
puts("");
}
*/
int ans=0;
for(int i=1;i<=tot;i++)
{
memset(done,0,sizeof(done));
//printf("i=%d\n",i);
if(dfs(i))ans++;
}
//printf("ans=%d\n",ans);
for(int i=1;i<=tot;i++)
if(linkr[i])
linkl[linkr[i]]=i;
for(int i=1;i<=tot;i++)
if(linkl[i])isl[i]=1;
//for(int i=1;i<=tot;i++)printf("%d ",linkr[i]);puts("");
for(int i=1;i<=tot;i++)
{
if(!linkl[i])
{
dfs2(i);
}
}
vector<int>rep;
for(int i=1;i<=tot;i++)if(!isl[i]&&!isr[i])rep.push_back(i);
printf("%d\n",(int)rep.size());
for(int i=0;i<rep.size();i++)
printf("%d%c",rep[i],i==rep.size()?'\n':' ');
}