【2014东莞市选】分组
2018-01-23 07:55
253 查看
【2014东莞市选】分组
(File IO): input:group.in output:group.outTime Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits Special Judge
Description
有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个分组中的字符串编号,编号对应字符串的输入顺序。数字之间用一个空格隔开。如果分组方案不唯一,输出任意一种即可。
Sample Input
4 1 AA AB BB BA
Sample Output
2 2 1 2 2 3 4
Data Constraint
50%的数据n<=100
100%的数据n<=5000,k<=550
最开始的思路:
将串们排序,将k位的前缀与后缀编号。
贪心,若某前缀有分组,那么塞进去,否则塞进后缀的分组,再否则新建分组,然而显然是错的:
4 2 AABC ADBC ADXY AAXX
这样会将1,2分组,导致不是最优
于是我考虑按照前缀的顺序加入,也是错的:
4 2 AABC AABD CCBD CDBC
同理。
于是我按照后缀的顺序重做,取最小值,当然还是错的!
——只是坑到了90+分
正解:
假设单词前缀集合为{A1..n1},后缀的集合为{B1..n2},每个单词可以用AiBj表示,于是这就符合二分图的定义了。
网络流。源点连向所有Ai,权为1,割掉这条边表示选择这个前缀,所有Bi连向汇点,权为1,割掉表明选择这个后缀,每个单词为一条边,权为∞,若ST连通,则说明还有单词没被选到,答案就是最小割。
要找到组内的元素,就要知道割掉哪些边,那么怎么找割边呢?
想到残余网络中割边权为0,但权为0时一定是割边吗?不是的:
S到T有两条路径,但只能跑一个单位的流,图中有两条权为0的边,但明显仅有连向T的边是割边。
那么就换一种方式判断是不是割边:从S开跑,如果能到达的点是靠T那一边的Bi,在流完的情况下是不可能到汇点的,那么Bi一定被割掉,反之不被割掉(最小割的情况下不可能再多割一条边),如果能到达靠S那一边的Ai,那么Ai一定不被割掉,①直接连边②上图的情况,通过反向弧到达,反之若不能到达Ai,则一定被割掉。
这样一来问题就迎刃而解了。
#include<cstring> #include<cstdio> #include<algorithm> #define N 5010 #define L 560 #define min(a,b) (a<b?a:b) using namespace std; int n,k,cnt[2],ex[2] ,no [2],top=1,fir[N*2],las[N*2],nex[4*N],to[4*N],v[4*N]; int own[2*N],head[2*N],nxt[2*N],tot,S,T,h[N*2],vh[N*2],sta ,que[N*2],H; bool vis ,used ; struct str{int p,el[L];}pre ,suf ; char c[L]; bool sm(str a,str b){ for(int i=1;i<=k;i++){ if(a.el[i]<b.el[i])return 1; if(a.el[i]>b.el[i])return 0; }return 0; } bool eq(str a,str b){ for(int i=1;i<=k;i++)if(a.el[i]!=b.el[i])return 0;return 1; } void link(int x,int y,int val){ to[++top]=y;nex[top]=0;v[top]=val; if(fir[x])nex[las[x]]=top;else fir[x]=top;las[x]=top; } void qlink(int x,int y){ own[++tot]=y;nxt[tot]=head[x];head[x]=tot; } int flow(int x,int fl){ if(x==T)return fl; int mn=T+10,i,j,y,f; for(i=fir[x],j=las[x];i;j=i,i=nex[i])if(v[i]){ if(h[x]==h[y=to[i]]+1){ if(f=flow(y,min(fl,v[i]))){ nex[las[x]]=fir[x];nex[j]=0;fir[x]=i;las[x]=j; v[i]-=f;v[i^1]+=f; return f; }if(h[S]>T)return 0; }mn=min(mn,h[y]+1); } if(!--vh[h[x]])h[S]=T+10; ++vh[h[x]=mn];return 0; } int main(){ freopen("group.in","r",stdin); freopen("group.out","w",stdout); scanf("%d %d\n",&n,&k); for(int i=1,l;i<=n;i++){ memset(c,0,sizeof(c));scanf("%s",c+1);l=strlen(c+1); pre[i].p=suf[i].p=i; for(int o=1;o<=k;o++)pre[i].el[o]=c[o]-'A',suf[i].el[o]=c[l-o+1]-'A'; }sort(pre+1,pre+n+1,sm);sort(suf+1,suf+n+1,sm); for(int i=1;i<=n;i++)no[pre[i].p][0]=(i==1 || !eq(pre[i],pre[i-1]))?++cnt[0]:cnt[0]; for(int i=1;i<=n;i++)no[suf[i].p][1]=(i==1 || !eq(suf[i],suf[i-1]))?++cnt[1]:cnt[1]; S=cnt[0]+cnt[1]+1;T=S+1; for(int i=1;i<=cnt[0];i++)link(S,i,1),link(i,S,0); for(int i=1;i<=cnt[1];i++)link(i+cnt[0],T,1),link(T,cnt[0]+i,0); for(int i=1;i<=n;i++){ int x=no[i][0],y=no[i][1]; link(x,y+cnt[0],n+n);link(y+cnt[0],x,0); qlink(x,i);qlink(y+cnt[0],i); } int tot=0;vh[0]=T;while(h[S]<=T)tot+=flow(S,n+n); printf("%d",tot); for(H=0,vis[que[T=1]=S]=1;H^T;) for(int x=que[++H],i=fir[x],y;i;i=nex[i]) if(v[i] && !vis[y=to[i]])vis[que[++T]=y]=1; for(int i=1;i<=cnt[0];i++)if(!vis[i]){ tot=0;for(int o=head[i];o;o=nxt[o])if(!used[own[o]])used[sta[++tot]=own[o]]=1; if(tot){printf("\n%d",tot);while(tot)printf(" %d",sta[tot--]);} } for(int i=cnt[0]+1;i<=cnt[0]+cnt[1];i++)if(vis[i]){ tot=0;for(int o=head[i];o;o=nxt[o])if(!used[own[o]])used[sta[++tot]=own[o]]=1; if(tot){printf("\n%d",tot);while(tot)printf(" %d",sta[tot--]);} } fclose(stdin);fclose(stdout); return 0; }
相关文章推荐
- 【JZOJ5537】【2014东莞市选】分组(网络流)
- jzoj5537 [2014东莞市选]分组 二分图
- 最小割求方案 & jzoj5537 【2014东莞市选】分组
- 【2014东莞市选】分组
- jzoj 5537. 【2014东莞市选】分组 最小割
- January 22nd 模拟赛A&B T3 【2014东莞市选】分组 Solution
- 【NOIP2014八校联考第2场第2试9.28】分组(group)
- 【NOIP2014八校联考第2场第2试9.28】分组(group)
- 可在广域网部署运行的QQ高仿版 -- GG2014 完美版!新增支持:聊天记录、好友分组、托盘闪动消息提醒、登录状态、GIF动态表情
- 【JZOJ3854】【NOIP2014八校联考第2场第2试9.28】分组(group)
- 【东莞市选2014】能源大亨(energy.pas/cpp) //2018.1.25
- jzoj 5535. 【2014东莞市选】登机 dp
- jzoj 5536. 【2014东莞市选】游戏 水题
- JZOJ 1846. 【东莞市选2014】能源大亨(energy.pas/cpp)
- JZOJsenior5536.【2014东莞市选】游戏
- 东莞市2014年市队选拔赛 分组 构造二分图最小覆盖方案
- JZOJ5537.【2014东莞市选】【JSOI2014】病毒分类
- BZOJ3524 [Poi2014]Couriers 主席树(模板)
- 在SQL Server2005/2008中对记录进行分组,并获得每组前N条记录
- 论文阅读(2014-1)----a new collaborative filtering-based recommender system for manufacturing appstore: which applications would be useful to your busines?