时间很紧……没办法写总结……
切了poj6题和bzoj2题,总的来说这个东西不难,而且变形也不多。主要是要会建图,建图的话要找到每个东西的两种状态,然后再对限制条件建边。
推荐博客:http://blog.csdn.net/jarjingx/article/details/8521690(废话多但是里面总结的挺到位的,特别是建边四种模型,建议先看论文和课件再看这个博客)
然后也不多了……也就是最后答案是否要输出?如果不用就直接判断,如果用那是否需要字典序最小,如果不需要那就拓扑直接搞,如果需要就直接暴力染色判断(没写过但是白书里面有而且翻到两个大神的代码似乎还不错?:http://blog.csdn.net/u013532224/article/details/39739959;http://blog.163.com/shengrui_step/blog/static/20870918720141201262750/……)
更多的有时间再来吧……
就不吐槽最近的进度,而且小高一一来机房好吵!!!
2014.12.26------------------------------------------------------------------------------------
写一下求任意一组解的算法流程吧:
1)跑tarjan,然后看每个和他对立的点是否在一个scc中。如果是,那么此图无解。
2)如果点都满足1。那么缩点建图,不过边要建成与原来相反(link数组是为了防止某个scc有大量点连向另一个scc)
3)dfs。如果某个点还没被选中,那么就选他,然后把他的对立点的后继都弄成不选。
如果是字典序最小:
建完图后直接dfs。for一边每个店:如果某个点和他的对立点都没有被选中,先把这个点弄为选,跑dfs看是否矛盾,矛盾就把图复原一下再把这个点的对立点弄为选,跑dfs,如果还是不行就无解了……
-------------------------------------------------------------------------------------
按照大神博客推荐的顺序切
POJ - 3207 Ikki's Story IV - Panda's Trick
http://www.cnblogs.com/Macaulish/p/4181301.html
POJ - 3683 Priest John's Busiest Day
每对过密不是在第一个时间段结婚就是在第二个时间段结婚。
然后如果一对过密和另一对过密结婚世界重合了就连另一个时间段。
最后拓扑找方案
type arr=record toward,next:longint; end; const maxn=20000; maxm=500000; var edge:array[0..maxm]of arr; dfn,low,f1,f2,num,color,p,scc,a,b,c,link,rec:array[0..maxn]of longint; chose:array[0..maxn]of boolean; time,tot,sum,n,tail:longint; function calc(ch:char):longint; begin exit(ord(ch)-48); end; procedure add1(i,j:longint); begin inc(tot); edge[tot].toward:=j; edge[tot].next:=f1[i]; f1[i]:=tot; end; procedure add2(i,j:longint); begin inc(tot); edge[tot].toward:=j; edge[tot].next:=f2[i]; f2[i]:=tot; inc(num[j]); end; procedure tarjan(x:longint); var i,too:longint; begin inc(time); dfn[x]:=time; low[x]:=time; chose[x]:=true; inc(tail); p[tail]:=x; i:=f1[x]; while i>0 do begin too:=edge[i].toward; if dfn[too]=0 then begin tarjan(too); if low[x]>low[too] then low[x]:=low[too]; end else if chose[too] and (dfn[too]<low[x]) then low[x]:=dfn[too]; i:=edge[i].next; end; if low[x]=dfn[x] then begin inc(sum); repeat too:=p[tail]; chose[too]:=false; scc[too]:=sum; dec(tail); until x=too; end; end; function ok:boolean; var i:longint; begin for i:=1 to n<<1 do if dfn[i]=0 then tarjan(i); for i:=1 to n do if scc[i]=scc[i+n] then exit(false); exit(true); end; procedure dfs(x:longint); var i,too:longint; begin color[x]:=2; i:=f2[x]; while i>0 do begin too:=edge[i].toward; if color[too]=0 then dfs(too); i:=edge[i].next; end; end; function check(i,j,k,l:longint):boolean; begin exit(not ((i>=l) or (k>=j))) end; procedure outo(x,y:longint); begin if x<600 then write(0); write(x div 60,':'); x:=x mod 60; if x<10 then write(0); write(x,' '); if y<600 then write(0); write(y div 60,':'); y:=y mod 60; if y<10 then write(0); write(y); writeln; end; procedure into; var i,j:longint; s:string; begin readln(n); time:=0; sum:=0; for i:=1 to n do begin readln(s); while s[length(s)]=' ' do delete(s,length(s),1); a[i]:=calc(s[1])*600+calc(s[2])*60+calc(s[4])*10+calc(s[5]); delete(s,1,6); b[i]:=calc(s[1])*600+calc(s[2])*60+calc(s[4])*10+calc(s[5]); delete(s,1,6); val(s,c[i]); end; for i:=1 to n-1 do for j:=i+1 to n do begin if check(a[i],a[i]+c[i],a[j],a[j]+c[j]) then begin add1(i,j+n); add1(j,i+n); end; if check(a[i],a[i]+c[i],b[j]-c[j],b[j]) then begin add1(i,j); add1(j+n,i+n); end; if check(b[i]-c[i],b[i],a[j],a[j]+c[j]) then begin add1(i+n,j+n); add1(j,i); end; if check(b[i]-c[i],b[i],b[j]-c[j],b[j]) then begin add1(i+n,j); add1(j+n,i); end; end; end; procedure work; var i,x,too,head,tail:longint; begin if not ok then begin writeln('NO'); exit; end; writeln('YES'); for x:=1 to n<<1 do begin i:=f1[x]; while i>0 do begin too:=edge[i].toward; if (scc[too]<>scc[n]) and (link[scc[too]]<>scc[n]) then begin link[scc[too]]:=scc[n]; add2(scc[too],scc[n]); end; i:=edge[i].next; end; end; tail:=0; head:=1; for i:=1 to sum do if num[i]=0 then begin inc(tail); p[tail]:=i; end; while head<=tail do begin x:=p[head]; inc(head); i:=f2[x]; while i>0 do begin too:=edge[i].toward; dec(num[too]); if num[too]=0 then begin inc(tail); p[tail]:=too; end; i:=edge[i].next; end; end; for i:=1 to n do begin rec[scc[i]]:=scc[i+n]; rec[scc[i+n]]:=scc[i]; end; for i:=1 to sum do if color[p[i]]=0 then begin color[p[i]]:=1; dfs(rec[p[i]]); end; for i:=1 to n do if color[scc[i]]=1 then outo(a[i],a[i]+c[i]) else outo(b[i]-c[i],b[i]); end; begin into; work; end.
POJ - 3678 Katu Puzzle
这个题强烈建议自己写!!
各种情况的分类我也是醉了,写完后再也不担心不会建图了……
(找到某个建的比我的好比我的容易的大神的建法:
a and b ==1 , !a->a , !b -> b
a and b ==0 , a->!b , b->!a
a or b ==1 , !a->b , !b->a
a or b ==0 , a->!a , b->!b
a xor b ==1 , a->!b,!b->a,!a->b,b->!a
a xor b ==0 , a->b,b->a,!a->!b,!b->!a)
type arr=record toward,next:longint; end; const maxn=3000; maxm=5000000; var edge:array[0..maxm]of arr; chose:array[0..maxn]of boolean; dfn,low,first,p,scc:array[0..maxn]of longint; time,tot,n,m,tail,sum:longint; procedure add(j,k:longint); begin inc(tot); edge[tot].toward:=k; edge[tot].next:=first[j]; first[j]:=tot; end; procedure tarjan(x:longint); var i,too:longint; begin inc(time); dfn[x]:=time; low[x]:=time; inc(tail); p[tail]:=x; chose[x]:=true; i:=first[x]; while i>0 do begin too:=edge[i].toward; if dfn[too]=0 then begin tarjan(too); if low[x]>low[too] then low[x]:=low[too]; end else if chose[too] and (dfn[too]<low[x]) then low[x]:=dfn[too]; i:=edge[i].next; end; if low[x]=dfn[x] then begin inc(sum); repeat too:=p[tail]; dec(tail); chose[too]:=false; scc[too]:=sum; until x=too; end; end; procedure into; var i,j,k,l:longint; ch:char; begin readln(n,m); for i:=1 to m do begin read(j,k,l,ch); readln(ch); case ch of 'A':if l=0 then begin add(j,k+n); add(k,j+n); end else begin add(j+n,j); add(k+n,k); add(j,k); add(k,j); end; 'O':if l=0 then begin add(j,j+n); add(k,k+n); add(j+n,k+n); add(k+n,j+n); end else begin add(j+n,k); add(k+n,j); end; 'X':if l=0 then begin add(j,k); add(k,j); add(j+n,k+n); add(k+n,j+n); end else begin add(j,k+n); add(k,j+n); end; end; end; end; procedure work; var i:longint; begin for i:=0 to n<<1-1 do if dfn[i]=0 then tarjan(i); for i:=0 to n-1 do if scc[i]=scc[i+n] then begin writeln('NO'); exit; end; writeln('YES'); end; begin into; work; end.
POJ - 3648 Wedding
这题和上面某道类似,调了很久的原因是因为要输出的是和新娘坐在同一边而不是另一边(英语差所以题目看的hehe)
然后调试时自己被自己邪恶的内心搞笑到了(各种百合各种基……)
type arr=record toward,next:longint; end; const maxm=1000000; maxn=90000; var edge:array[0..maxm]of arr; color,num,first,rec,f2,dfn,low,scc,p,link:array[0..maxn]of longint; chose:array[0..maxn]of boolean; n,m,tot,time,sum,tail:longint; procedure add1(j,k:longint); begin inc(tot); edge[tot].toward:=k; edge[tot].next:=first[j]; first[j]:=tot; end; procedure add2(j,k:longint); begin inc(tot); edge[tot].toward:=k; edge[tot].next:=f2[j]; f2[j]:=tot; inc(num[k]); end; procedure dfs(x:longint); var i,too:longint; begin color[x]:=2; i:=f2[x]; while i>0 do begin too:=edge[i].toward; if color[too]=0 then dfs(too); i:=edge[i].next; end; end; procedure tarjan(x:longint); var i,too:longint; begin inc(time); dfn[x]:=time; low[x]:=time; chose[x]:=true; inc(tail); p[tail]:=x; i:=first[x]; while i>0 do begin too:=edge[i].toward; if dfn[too]=0 then begin tarjan(too); if low[x]>low[too] then low[x]:=low[too]; end else if chose[too] and (dfn[too]<low[x]) then low[x]:=dfn[too]; i:=edge[i].next; end; if low[x]=dfn[x] then begin inc(sum); num[sum]:=0; repeat too:=p[tail]; dec(tail); scc[too]:=sum; chose[too]:=false; until x=too; end; end; procedure into; var x1,x2,y1,y2,i,j:longint; s:string; begin fillchar(dfn,sizeof(dfn),0); fillchar(low,sizeof(low),0); fillchar(first,sizeof(first),0); fillchar(f2,sizeof(f2),0); fillchar(color,sizeof(color),0); fillchar(link,sizeof(link),0); fillchar(chose,sizeof(chose),false); tot:=0; time:=0; tail:=0; sum:=0; for i:=1 to m do begin readln(s); s:=s+' '; j:=pos(' ',s); val(copy(s,1,j-2),x1); if s[j-1]='h' then begin x2:=x1; x1:=x1+n; end else x2:=x1+n; delete(s,1,j); j:=pos(' ',s); val(copy(s,1,j-2),y1); if s[j-1]='h' then begin y2:=y1; y1:=y1+n; end else y2:=y1+n; add1(x1,y2); add1(y1,x2); end; add1(0,0+n); end; procedure work; var head,tail,o,j,x,too,i:longint; begin for i:=0 to n<<1-1 do if dfn[i]=0 then tarjan(i); for i:=0 to n-1 do if scc[i]=scc[i+n] then begin writeln('bad luck'); exit; end; for x:=0 to n<<1-1 do begin i:=first[x]; while i>0 do begin too:=edge[i].toward; if (scc[too]<>scc[x]) and (link[scc[too]]<>scc[x]) then begin link[scc[too]]:=scc[x]; add2(scc[too],scc[x]); end; i:=edge[i].next; end; end; head:=1; tail:=0; for i:=1 to sum do if num[i]=0 then begin inc(tail); p[tail]:=i; end; while head<=tail do begin x:=p[head]; inc(head); i:=f2[x]; while i>0 do begin too:=edge[i].toward; dec(num[too]); if num[too]=0 then begin inc(tail); p[tail]:=too; end; i:=edge[i].next; end; end; for i:=0 to n-1 do begin rec[scc[i]]:=scc[i+n]; rec[scc[i+n]]:=scc[i]; end; for i:=1 to sum do if color[p[i]]=0 then begin color[p[i]]:=1; dfs(rec[p[i]]); end; //j:=color[scc[0]]; for i:=1 to n-1 do if color[scc[i]]=2 then write(i,'w ') else write(i,'h '); writeln; end; begin while true do begin readln(n,m); if n=0 then break; into; work; end; end.
POJ - 2723 Get Luffy Out
这题要二分答案建图判断
一对钥匙不能同时取就是两个只能取一个
一个门一定要开就是两个都不能不取
然后二分答案建图去判断是否能到达某山门
type arr=record toward,next:longint; end; const maxn=300000; maxm=600000; var edge:array[0..maxm]of arr; dfn,low,first,scc,p,key1,key2,door1,door2:array[0..maxn]of longint; chose:array[0..maxn]of boolean; n,m,time,tot,sum,tail,nn:longint; procedure add(j,k:longint); begin inc(tot); edge[tot].toward:=k; edge[tot].next:=first[j]; first[j]:=tot; end; procedure tarjan(x:longint); var i,too:longint; begin inc(time); dfn[x]:=time; low[x]:=time; inc(tail); p[tail]:=x; chose[x]:=true; i:=first[x]; while i>0 do begin too:=edge[i].toward; if dfn[too]=0 then begin tarjan(too); if low[x]>low[too] then low[x]:=low[too]; end else if chose[too] and (dfn[too]<low[x]) then low[x]:=dfn[too]; i:=edge[i].next; end; if low[x]=dfn[x] then begin inc(sum); repeat too:=p[tail]; dec(tail); chose[too]:=false; scc[too]:=sum; until x=too; end; end; function check(x:longint):boolean; var i:longint; begin fillchar(dfn,sizeof(dfn),0); fillchar(low,sizeof(low),0); fillchar(first,sizeof(first),0); fillchar(chose,sizeof(chose),false); time:=0; tot:=0; tail:=0; sum:=0; for i:=1 to n do begin add(key1[i],key2[i]+nn); add(key2[i],key1[i]+nn); end; for i:=1 to x do begin add(door1[i]+nn,door2[i]); add(door2[i]+nn,door1[i]); end; for i:=0 to nn<<1-1 do if dfn[i]=0 then tarjan(i); for i:=0 to nn-1 do if scc[i]=scc[i+nn] then exit(false); exit(true) end; procedure work; var i,left,right,ans,mid:longint; begin nn:=n<<1; for i:=1 to n do readln(key1[i],key2[i]); for i:=1 to m do readln(door1[i],door2[i]); left:=0; right:=m+1; while left+1<right do begin mid:=(left+right)>>1; if check(mid) then left:=mid else right:=mid; end; writeln(left); end; begin while true do begin readln(n,m); if n=0 then break; work; end; end.
POJ - 2749 Building roads
每两个点有四种情况:第一个点连s1第二个点s1;第一个点连s1第二个点连s2;第一个点连s2第二个点连s1;第一个点连s2第二个点连s2。
然后二分最大值,如果两个点在上面四种情况的某一种情况中>最大值就不能有这种情况,也就是要选择其他种(具体看程序吧)
type arr=record toward,next:longint; end; const maxm=3000000; maxn=90000; mm=23333333; var edge:array[0..maxm]of arr; low,dfn,first,scc,p:array[0..maxn]of longint; num,num1,num2:array[0..maxn,1..2]of longint; chose:array[0..maxn]of boolean; time,tot,n,m1,m2,tail,sum,dis:longint; procedure add(j,k:longint); begin inc(tot); edge[tot].toward:=k; edge[tot].next:=first[j]; first[j]:=tot; end; procedure tarjan(x:longint); var i,too:longint; begin inc(time); dfn[x]:=time; low[x]:=time; inc(tail); p[tail]:=x; chose[x]:=true; i:=first[x]; while i>0 do begin too:=edge[i].toward; if dfn[too]=0 then begin tarjan(too); if low[x]>low[too] then low[x]:=low[too]; end else if chose[too] and (dfn[too]<low[x]) then low[x]:=dfn[too]; i:=edge[i].next; end; if low[x]=dfn[x] then begin inc(sum); repeat too:=p[tail]; chose[too]:=false; scc[too]:=sum; dec(tail); until x=too; end; end; function check(x:longint):boolean; var i,j:longint; begin fillchar(dfn,sizeof(dfn),0); fillchar(low,sizeof(low),0); fillchar(first,sizeof(first),0); fillchar(chose,sizeof(chose),false); time:=0; tot:=0; tail:=0; for i:=1 to m1 do begin add(num1[i,1],num1[i,2]+n); add(num1[i,2],num1[i,1]+n); add(num1[i,1]+n,num1[i,2]); add(num1[i,2]+n,num1[i,1]); end; for i:=1 to m2 do begin add(num2[i,1],num2[i,2]); add(num2[i,2],num2[i,1]); add(num2[i,1]+n,num2[i,2]+n); add(num2[i,2]+n,num2[i,1]+n); end; for i:=1 to n-1 do for j:=i+1 to n do begin if num[i,1]+num[j,1]>x then begin add(i,j+n); add(j,i+n); end; if num[i,1]+num[j,2]+dis>x then begin add(i,j); add(j+n,i+n); end; if num[i,2]+num[j,1]+dis>x then begin add(i+n,j+n); add(j,i); end; if num[i,2]+num[j,2]>x then begin add(i+n,j); add(j+n,i); end; end; for i:=1 to n<<1 do if dfn[i]=0 then tarjan(i); for i:=1 to n do if scc[i]=scc[i+n] then exit(false); exit(true); end; procedure into; var i,sx1,sy1,sx2,sy2,j,k:longint; begin readln(n,m1,m2); read(sx1,sy1,sx2,sy2); dis:=abs(sx1-sx2)+abs(sy1-sy2); for i:=1 to n do begin readln(j,k); num[i,1]:=abs(j-sx1)+abs(k-sy1); num[i,2]:=abs(j-sx2)+abs(k-sy2); end; for i:=1 to m1 do readln(num1[i,1],num1[i,2]); for i:=1 to m2 do readln(num2[i,1],num2[i,2]); end; procedure work; var left,right,mid:longint; begin left:=0; right:=mm; while left<right do begin mid:=(left+right)>>1; if check(mid) then right:=mid else left:=mid+1; end; if left>=mm then writeln(-1) else writeln(left) end; begin into; work; end.
bzoj1823: [JSOI2010]满汉全席
我去这题好水……题目老长结果&……
直接连通判断就行了
type arr=record toward,next:longint; end; const maxm=50000; maxn=2000; var dfn,low,first,scc,p:array[0..maxn]of longint; chose:array[0..maxn]of boolean; time,tot,n,m,tail,sum,t:longint; edge:array[0..maxm]of arr; procedure add(j,k:longint); begin inc(tot); edge[tot].toward:=k; edge[tot].next:=first[j]; first[j]:=tot; end; procedure tarjan(x:longint); var i,too:longint; begin inc(time); dfn[x]:=time; low[x]:=time; chose[x]:=true; inc(tail); p[tail]:=x; i:=first[x]; while i>0 do begin too:=edge[i].toward; if dfn[too]=0 then begin tarjan(too); if low[x]>low[too] then low[x]:=low[too]; end else if chose[too] and (dfn[too]<low[x]) then low[x]:=dfn[too]; i:=edge[i].next; end; if low[x]=dfn[x] then begin inc(sum); repeat too:=p[tail]; dec(tail); chose[too]:=false; scc[too]:=sum; until x=too; end; end; procedure into; var i,x1,x2,y1,y2:longint; ch:char; begin readln(n,m); fillchar(dfn,sizeof(dfn),0); fillchar(low,sizeof(low),0); fillchar(first,sizeof(first),0); fillchar(chose,sizeof(chose),false); tot:=0; time:=0; tail:=0; for i:=1 to m do begin read(ch); read(x1); if ch='m' then begin x2:=x1; x1:=x1+n; end else x2:=x1+n; read(ch); read(ch); readln(y1); if ch='m' then begin y2:=y1; y1:=y1+n; end else y2:=y1+n; add(x2,y1); add(y2,x1); end; end; function work:boolean; var i:longint; begin for i:=1 to n<<1 do if dfn[i]=0 then tarjan(i); for i:=1 to n do if scc[i]=scc[i+n] then exit(false); exit(true); end; begin readln(t); while t>0 do begin dec(t); into; if work then writeln('GOOD') else writeln('BAD'); end; end.
bzoj2199: [Usaco2011 Jan]奶牛议会
这题……求的不是某组解的答案而是奇奇怪怪的东西……那就用那个o(nm)的方法判断吧!
type arr=record toward,next:longint; end; const maxn=2333; maxm=50000; var edge:array[0..maxm]of arr; chose:array[0..maxn]of boolean; first:array[0..maxn]of longint; ans:array[0..maxn]of 0..2; n,m,tot:longint; procedure add(j,k:longint); begin inc(tot); edge[tot].toward:=k; edge[tot].next:=first[j]; first[j]:=tot; end; procedure dfs(x:longint); var i,too:longint; begin chose[x]:=true; i:=first[x]; while i>0 do begin too:=edge[i].toward; if not chose[too] then dfs(too); i:=edge[i].next; end; end; function check(x:longint):boolean; var i:longint; begin fillchar(chose,sizeof(chose),false); dfs(x); for i:=1 to n do if chose[i] and chose[i+n] then exit(false); exit(true); end; procedure into; var x1,x2,y1,y2,i:longint; ch:char; begin readln(n,m); for i:=1 to m do begin read(x1); read(ch); read(ch); if ch='Y' then x2:=x1+n else begin x2:=x1; x1:=x1+n; end; read(y1); read(ch); readln(ch); if ch='Y' then y2:=y1+n else begin y2:=y1; y1:=y1+n; end; add(x2,y1); add(y2,x1); end; end; procedure work; var i:longint; ok1,ok2:boolean; begin for i:=1 to n do begin ok1:=check(i); ok2:=check(i+n); if not (ok1 or ok2) then begin writeln('IMPOSSIBLE'); exit; end; if ok1 then if ok2 then ans[i]:=0 else ans[i]:=1 else ans[i]:=2; end; for i:=1 to n do case ans[i] of 0:write('?'); 1:write('Y'); 2:write('N'); end; end; begin into; work; end.
hdu 1814 Peaceful Commission
这题的读入我也是醉了……似乎没有说是多组数据啊结果……调了一节晚自修后才发现……
因为要字典序最小所以用白书中的方法……
建图一样有点傻,我是把点认为是人……结果大家都是把点认为是党员……然后我就华丽丽地把节点数升级到了4n……
type arr=record toward,next:longint; end; const maxn=60000; maxm=2000000; var first,p:array[0..maxn]of longint; edge:array[0..maxm]of arr; color:array[0..maxn]of boolean; tail,tot,n,m,long,i:longint; procedure add(j,k:longint); begin inc(tot); edge[tot].toward:=k; edge[tot].next:=first[j]; first[j]:=tot; end; function dfs(x:longint):boolean; var i,too:longint; flag:boolean; begin if color[x+long] then dfs:=false else if color[x] then dfs:=true else begin flag:=true; color[x]:=true; inc(tail); p[tail]:=x; i:=first[x]; while i>0 do begin too:=edge[i].toward; if not dfs(too) then begin flag:=false; break; end; i:=edge[i].next; end; dfs:=flag; end; end; procedure into; var i,j,k:longint; begin fillchar(color,sizeof(color),false); fillchar(first,sizeof(first),0); tail:=0; long:=n*2; tot:=0; for i:=1 to n do begin j:=i*2; add(j-1,j+long); add(j+long,j-1); add(j,j-1+long); add(j-1+long,j); end; for i:=1 to m do begin readln(j,k); add(j,k+long); add(k,j+long); end; end; function work:boolean; var i,j:longint; flag:boolean; begin flag:=true; for i:=1 to long do if not (color[i] or color[i+long]) then begin tail:=0; if not dfs(i) then begin for j:=tail downto 1 do color[p[j]]:=false; if not dfs(i+long) then begin flag:=false; break; end; end; end; work:=flag; end; begin while not eof do begin readln(n,m); into; if work then begin for i:=1 to long do if color[i] then writeln(i); end else writeln('NIE'); end; end.