hdu 3957 Street Fighter

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3957

/*第一种方法是建立一个有2*N行,3*N列的矩阵,行代表的是选择哪些人的哪一个形态,前2*N列代表的是N个人的两种形态,后面N列表示选择了某个人,

这样我们可以这么理解,前2*N列是我们必须至少覆盖一次的,后N列是我么至多覆盖一次的,

那么我们就在前2*N列进行重复覆盖,后面N列进行精确覆盖,

此外,判断是否得到了一组解,只要判断前2*N列是否已经被完全覆盖了即可。这个矩阵的规模是50*75的。*/

/*第二种方法是建立一个2*N行2*N列的矩阵,直接跑重复覆盖,此外用一个数组标记某一个人是否被选择过,

如果一个人的某一形态被选择过,那么另外一个形态对应的行就不能选择,这个矩阵的规模是50*50的。*/

由于好长时间没写过重复覆盖了,以为第一次求出来的就是最优解。然后各种WA。。

建边的时候需要注意细节,搞不好就弄错了。

ContractedBlock.gif ExpandedBlockStart.gif View Code
  1 # include<stdio.h>
2 # include<string.h>
3 # define cc 100
4 # define rr 60
5 # define V 6000
6 int U[V],D[V];
7 int L[V],R[V];
8 int C[V],ROW[V];
9 int H[rr],S[cc];
10 int mark[rr],visit[27],size,ak;
11 struct node{
12 int m;
13 int num1,num2;
14 int a[11][2],b[11][2];
15 }s[27];
16 void Link(int r,int c)
17 {
18 S[c]++;
19 C[size]=c;
20 ROW[size]=r;
21 U[size]=U[c];D[U[c]]=size;
22 D[size]=c;U[c]=size;
23 if(H[r]==-1) H[r]=L[size]=R[size]=size;
24 else
25 {
26 L[size]=L[H[r]];R[L[H[r]]]=size;
27 R[size]=H[r];L[H[r]]=size;
28 }
29 size++;
30 }
31 void remove(int c)
32 {
33 int i;
34 for(i=D[c];i!=c;i=D[i])
35 {
36 L[R[i]]=L[i];
37 R[L[i]]=R[i];
38 }
39 }
40 void resume(int c)
41 {
42 int i;
43 for(i=U[c];i!=c;i=U[i])
44 L[R[i]]=R[L[i]]=i;
45 }
46 int h()
47 {
48 int i,j,k,count=0;
49 bool hash[cc];
50 memset(hash,0,sizeof(hash));
51 for(i=R[0];i;i=R[i])
52 {
53 if(hash[i]) continue;
54 hash[i]=1;
55 count++;
56 for(j=D[i];j!=i;j=D[j])
57 for(k=R[j];k!=j;k=R[k])
58 hash[C[k]]=1;
59 }
60 return count;
61 }
62 void Dance(int k)
63 {
64 int j,i,c,Min;
65 if(k+h()>=ak) return;
66 if(!R[0])
67 {
68 if(k<ak) ak=k;
69 return;
70 }
71 for(Min=rr,i=R[0];i;i=R[i])
72 if(Min>S[i]) Min=S[i],c=i;
73 for(i=D[c];i!=c;i=D[i])
74 {
75 if(visit[mark[ROW[i]]]) continue;
76 visit[mark[ROW[i]]]=1;
77 remove(i);
78 for(j=R[i];j!=i;j=R[j])
79 remove(j);
80 Dance(k+1);
81 for(j=L[i];j!=i;j=L[j])
82 resume(j);
83 resume(i);
84 visit[mark[ROW[i]]]=0;
85 }
86 }
87 int main()
88 {
89 int i,j,ncase,t,n,sum[26],number,mob,k,c,r;
90 scanf("%d",&ncase);
91 for(t=1;t<=ncase;t++)
92 {
93 scanf("%d",&n);
94 sum[0]=1;
95 for(i=0;i<n;i++)
96 {
97 scanf("%d",&s[i].m);
98 scanf("%d",&s[i].num1);
99 for(k=0;k<s[i].num1;k++)
100 scanf("%d%d",&s[i].a[k][0],&s[i].a[k][1]);
101 if(s[i].m==2)
102 {
103 scanf("%d",&s[i].num2);
104 for(k=0;k<s[i].num2;k++)
105 scanf("%d%d",&s[i].b[k][0],&s[i].b[k][1]);
106 }
107 sum[i+1]=sum[i]+s[i].m;
108 }
109 c=sum[n]-1;
110 for(i=0;i<=c;i++)
111 {
112 S[i]=0;
113 U[i]=D[i]=i;
114 L[i+1]=i;R[i]=i+1;
115 }R[c]=0;
116 size=c+1;
117 r=0;
118 memset(H,-1,sizeof(H));
119 for(i=0;i<n;i++)
120 {
121 r++;
122 mark[r]=i;
123 for(j=0;j<s[i].num1;j++)
124 {
125 number=s[i].a[j][0];
126 mob=s[i].a[j][1];
127 Link(r,sum[number]+mob);
128 }
129 for(j=0;j<s[i].m;j++)
130 Link(r,sum[i]+j);
131 if(s[i].m==2)
132 {
133 r++;
134 mark[r]=i;
135 for(j=0;j<s[i].num2;j++)
136 {
137 number=s[i].b[j][0];
138 mob=s[i].b[j][1];
139 Link(r,sum[number]+mob);
140 }
141 for(j=0;j<s[i].m;j++)
142 Link(r,sum[i]+j);
143 }
144 }
145 memset(visit,0,sizeof(visit));
146 ak=n;
147 Dance(0);
148 printf("Case %d: %d\n",t,ak);
149 }
150 return 0;
151 }

 


 

转载于:https://www.cnblogs.com/183zyz/archive/2011/10/14/2211265.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值