[关闭]
@xiaoziyao 2020-10-22T08:34:12.000000Z 字数 2303 阅读 808

UVA10319 Manhattan解题报告

解题报告


UVA10319 Manhattan解题报告:

更好地阅读体验

题意

分析

神仙题。

对于每一行,套路地拆点:表示向左,表示向右;同样的对于每一列表示向上,表示向下。

然后,对于每一对起点终点,首先讨论不需要拐弯的特殊情况,即起点,终点处于同一行或同一列,这样我们直接强制确定某一行/列的方向就好了。

关于如何强制确定一个命题:将这个命题的反命题向这个命题连边,那么就一定无法选定这个命题的反命题了。

关于要拐弯的情况,以起点终点为例,我们需要保证以下命题成立:

意思就是第四行向左且第二列向上,或第四列向上且第一行向左。

这样我们就要想办法建出来图来满足这种形式的命题

有一个逻辑恒等式可以套上去:

(读者自证不难)

这样,我们就可以按照上述式子建图了。

注意要对于的大小关系分类讨论。

时间复杂度:

代码

记得有多组数据

  1. #include<stdio.h>
  2. const int maxn=30005,maxm=20005;
  3. int s,a,m,n,e,top,flg,T;
  4. int start[maxn],to[maxm],then[maxm],ans[maxn],stk[maxn],vis[maxn],rev[maxn],line[maxn],row[maxn];
  5. inline void add(int x,int y){//加边
  6. then[++e]=start[x],start[x]=e,to[e]=y;
  7. }
  8. int dfs(int x){//dfs实现2-SAT
  9. if(vis[rev[x]])
  10. return 0;
  11. if(vis[x])
  12. return 1;
  13. vis[x]=1,stk[++top]=x;
  14. for(int i=start[x];i;i=then[i]){
  15. int y=to[i];
  16. if(dfs(y)==0)
  17. return 0;
  18. }
  19. return 1;
  20. }
  21. inline void addedge(int a,int b,int c,int d){//
  22. //(a and b)or(c and d)
  23. //=(a or c)and(a or d)and(b or c)and(b or d)
  24. add(rev[a],c),add(rev[c],a);
  25. add(rev[a],d),add(rev[d],a);
  26. add(rev[b],c),add(rev[c],b);
  27. add(rev[b],d),add(rev[d],b);
  28. }
  29. int main(){
  30. scanf("%d",&T);
  31. while(T--){
  32. e=top=flg=0;
  33. scanf("%d%d%d",&s,&a,&m);
  34. n=s+a;
  35. for(int i=1;i<=n;i++){
  36. rev[i]=n+i,rev[n+i]=i;
  37. start[i]=vis[i]=ans[i]=0;
  38. start[n+i]=vis[n+i]=ans[n+i]=0;
  39. }
  40. for(int i=1;i<=s;i++)
  41. row[i]=i;
  42. for(int i=1;i<=a;i++)
  43. line[i]=s+i;
  44. for(int i=1;i<=m;i++){
  45. //as for row:
  46. //a:<--------
  47. //rev[a]:--->
  48. //
  49. //as for line:
  50. //b:^ rev[b]:|
  51. // | |
  52. // | v
  53. int a,b,c,d;
  54. scanf("%d%d%d%d",&a,&b,&c,&d);
  55. if(a==c&&b==d)//起点,终点重合
  56. continue;
  57. a=row[a],b=line[b],c=row[c],d=line[d];//确定行,列
  58. if(a==c){//相同行
  59. if(b<d)
  60. add(a,rev[a]);
  61. if(b>d)
  62. add(rev[a],a);
  63. }
  64. if(b==d){//相同列
  65. if(a<c)
  66. add(b,rev[b]);
  67. if(a>c)
  68. add(rev[b],b);
  69. }
  70. if(a!=c&&b!=d){//普通情况
  71. //addedge(a,b,c,d):(a and b)or(c and d)
  72. if(a<c&&b<d)
  73. addedge(rev[a],rev[d],rev[b],rev[c]);
  74. if(a<c&&b>d)
  75. addedge(a,rev[d],rev[b],c);
  76. if(a>c&&b<d)
  77. addedge(b,rev[c],rev[a],d);
  78. if(a>c&&b>d)
  79. addedge(b,c,a,d);
  80. }
  81. }
  82. for(int i=1;i<=n;i++){//2-SAT
  83. top=0,ans[i]=0;
  84. if(dfs(i)==0){
  85. for(int j=1;j<=top;j++)
  86. vis[stk[j]]=0;
  87. top=0,ans[i]=1;
  88. if(dfs(n+i)==0){
  89. puts("No");
  90. flg=1;
  91. break;
  92. }
  93. }
  94. }
  95. if(flg==0)
  96. puts("Yes");
  97. }
  98. return 0;
  99. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注