Problem
有n个字符串,给这些字符串分组,使得每个字符串属于且仅属于一个组。
对于一个合法的分组,至少满足以下两个条件种的一个:
1. 所有字符串的k前缀相同(即前k个字母相同)
2. 所有字符串的k后缀相同(即后k个字母相同)
你需要给这些字符串分组,使得所分的组数最少。
Input
第一行两个整数n,k(1<=n<=5000, 1<=k<=550),分别表示字符串的数量以及题述中的参数k。
接下来有n行,每行一个字符串,字符串的长度至少为k,且不会超过550。
Output
第一行一个整数m,表示最少的分组数目。
接下来m行,每行的第一个整数ti表示第i个分组的字符串数量,接下来有ti个整数,表示第i个分组中的字符串编号,编号对应字符串的输入顺序。数字之间用一个空格隔开。如果分组方案不唯一,输出任意一种即可。
题解
有点难想到是网络流,
看到分组,就应该向最小割方面想一下。
构图:超级源S向所有的前缀连一条容量为1的边,
所有后缀向超级汇T连一条容量为1的边。
同一个字符串的前缀向后缀连一条正无穷的边。
意义:割了哪一条边就是选前缀或者后缀,同一个字符串不能被割开。
输出方案:看看原本连向源点的边哪些被割掉了,哪些前缀就分成一组。
code
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 100003
#define db double
#define P putchar
#define G getchar
#define inf 998244353
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
int nxt[N*2],to[N*2],v[N*2],last[N],cur[N],tot;
int q[N],h[N],S,T,ans;
int n,m,t,id,k,p[N],a[N];
bool vis[N];
struct node
{
char p[606];
int len,id,ans,last;
}s[N];
bool cmp1(node a,node b)
{
for(int i=1;i<=k;i++)
{
if(a.p[i]<b.p[i])return 1;
if(a.p[i]>b.p[i])return 0;
}
return a.ans<b.ans;
}
bool cmp2(node a,node b)
{
for(int i=1;i<=k;i++)
{
if(a.p[a.len-i+1]<b.p[b.len-i+1])return 1;
if(a.p[a.len-i+1]>b.p[b.len-i+1])return 0;
}
return a.ans<b.ans;
}
bool cmp3(node a,node b){return a.id<b.id;}
bool cmp4(node a,node b){return a.last<b.last;}
bool diff(node a,node b)
{
for(int i=1;i<=k;i++)
if(a.p[i]!=b.p[i])return 1;
return 0;
}
bool diff1(node a,node b)
{
for(int i=1;i<=k;i++)
if(a.p[a.len-i+1]!=b.p[b.len-i+1])return 1;
return 0;
}
bool bfs()
{
int head=0,tail=1;
for(int i=0;i<=id;i++)h[i]=-1;
q[0]=S;h[S]=0;
while(head!=tail)
{
int now=q[head];head++;
for(int i=last[now];i;i=nxt[i])
if(v[i] && h[to[i]]==-1)
{
h[to[i]]=h[now]+1;
q[tail++]=to[i];
}
}
return h[T]!=-1;
}
int dfs(int x,int f)
{
if(x==T)return f;
int w,used=0;
for(int i=cur[x];i;i=nxt[i])
if(h[to[i]]==h[x]+1)
{
w=f-used;
w=dfs(to[i],min(w,v[i]));
v[i]-=w;v[i^1]+=w;
if(v[i])cur[x]=i;
used+=w;
if(used==f)return f;
}
if(!used)h[x]=-1;
return used;
}
void dinic()
{
while(bfs())
{
for(int i=0;i<=id;i++)
cur[i]=last[i];
ans+=dfs(S,n);
}
}
int dg(int k,int t)
{
if (k==T) return t;
int q=0;
for(int w=last[k];w;w=nxt[w])
if (v[w] && h[k]==h[to[w]]+1)
{
q=dg(to[w],min(t,v[w]));
if(q)
{
v[w]-=q;
v[w^1]+=q;
return q;
}
if (h[S]>id) return 0;
}
a[h[k]]--;
if (!a[h[k]]) h[S]=id+1;
h[k]++;
a[h[k]]++;
return 0;
}
void ins(int x,int y,int z)
{
nxt[++tot]=last[x];
to[tot]=y;
v[tot]=z;
last[x]=tot;
}
void dfs_(int x)
{
p[x]=1;
for(int i=last[x];i;i=nxt[i])
if(!p[to[i]] && v[i])
{
if(to[i]==705)
p[x]=1;
dfs_(to[i]);
}
}
int main()
{
tot=1;
read(n);read(k);
for(int i=1;i<=n;i++)
{
for(ch=G();ch<'A' || ch>'Z';ch=G());
for(s[i].len=0;'A'<=ch && ch<='Z';ch=G())s[i].p[++s[i].len]=ch;
s[i].ans=i;
}
S=1;T=2;
sort(s+1,s+1+n,cmp1);id=2;
for(int i=1;i<=n;i++)
{
if(diff(s[i],s[i-1]))id++;
s[i].id=id;
}
for(int i=3;i<=id;i++)
ins(S,i,1),ins(i,S,0);
t=id;
sort(s+1,s+1+n,cmp2);
for(int i=1;i<=n;i++)
{
if(diff1(s[i],s[i-1]))id++;
ins(s[i].id,id,inf);
ins(id,s[i].id,0);
s[i].last=id;
/*for(int j=1;j<=s[i].len;j++)
P(s[i].p[j]);
P('\n');*/
}
for(int i=t+1;i<=id;i++)
ins(i,T,1),ins(T,i,0);
//dinic();
a[0]=id;while(h[S]<=id)ans+=dg(S,inf);
write(ans);P('\n');
memset(p,0,sizeof(p));
memset(vis,0,sizeof(vis));
tot=0;dfs_(S);
sort(s+1,s+1+n,cmp3);
for(int i=1;i<=n;i++)
{
if(p[s[i].id])continue;
ans=0;
for(int j=i;j<=n && s[i].id==s[j].id;j++)ans++,vis[s[j].ans]=1;
if(ans)
{
write(ans),P(' ');
for(int j=i;j<=n && s[i].id==s[j].id;j++)write(s[j].ans),P(' ');
P('\n');
i=i+ans-1;
}
}
sort(s+1,s+1+n,cmp4);
for(int i=1;i<=n;i++)
{
if(!p[s[i].last])continue;
ans=0;t=0;
for(int j=i;j<=n && s[j].last==s[i].last;j++,t++)
if(!vis[s[j].ans])ans++;
if(ans)
{
write(ans),P(' ');
for(int j=i;j<=n && s[j].last==s[i].last;j++)
if(!vis[s[j].ans])write(s[j].ans),P(' ');
P('\n');
}
i=i+t-1;
}
}