这个题的做法我已经知道,就是先构造出图,用网络流算法走个最大流,由于只有插头插座两种,也可以用二分图(二部图)匹配,但是要我写代码,感觉很烦躁,拖了很久,终于用网络流A了它。
记录第一次用map,呵呵。因为老是要做查找操作,所以试试map,希望能省点时间。
构图方式如下:
加入超源点s和超收点t
s点到所有插座的容量为1(因为该插座只有一个)
设备要用的插头到t点的容量为该类型插头的个数(例如有3个设备是B插头,插头B到t的容量为3)
插头能直接插在插座上(名字相同),那么插座到插头的容量为无穷。
插头能通过交换器连接到插座上,该插座到插头的容量也为无穷,用最大流算法求出能输送多少到超收点。
再用设备数-该值即为所求。
先贴POJ上能过的较繁琐,但是可能更直观的代码:
View Code
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <string> 5 #include <map> 6 #include <queue> 7 using namespace std; 8 #define MAXN 300 9 #define INF 0x7fffffff 10 map<string,int> mp;//原插座和设备 11 map<string,int> c;//转换器 12 bool edge[MAXN][MAXN];//转换器的邻接矩阵 13 int ss,tt;//源点和汇点 14 int n,m; 15 int cur,ser;//设备和插座的点数,转换器中出现了多少种插头和插座 16 int resi[MAXN][MAXN]; //容量网络 17 bool sign[MAXN][MAXN]; //层次网络 18 int reach[MAXN][MAXN];//每个点的可到达点 19 int qua[MAXN];//每个点的可到达多少个点 20 int num[MAXN];//设备的数量要求 21 char a[MAXN][30];//存转换器中的插头插座名字 22 char aa[MAXN][30]; 23 void init1()//读入会议室提供的插座和设备所需插座 24 { 25 int i; 26 memset(num,0,sizeof(num)); 27 scanf("%d",&n); 28 for(i=0; i<n; ++i) 29 { 30 cin>>aa[i]; 31 mp[aa[i]] = i; 32 } 33 scanf("%d",&m); 34 cur = n-1; 35 for(i=0; i<m; ++i) 36 { 37 string d,dname; 38 cin>>dname>>d; 39 d = d+'d'; 40 map<string,int>::iterator it; 41 it = mp.find(d); 42 if(it != mp.end()) 43 ++num[(*it).second]; 44 else 45 { 46 mp[d] = ++cur; 47 strcpy(aa[cur],d.c_str()); 48 num[cur] = 1; 49 } 50 } 51 for(int i=0; i<n; ++i) 52 { 53 map<string,int>::iterator it; 54 string sq = aa[i]; 55 sq = sq + 'd'; 56 it = mp.find(sq); 57 if(it != mp.end()) 58 resi[i][(*it).second] = INF; 59 } 60 ss = cur+1; 61 tt = cur+2; 62 } 63 void init2()//读入转换器的情况,构造出转换的邻接矩阵 64 { 65 int k; 66 scanf("%d",&k); 67 memset(edge,0,sizeof(edge)); 68 ser=-1; 69 while(k--) 70 { 71 string s2,s1; 72 cin>>s2>>s1; 73 map<string,int>::iterator it1,it2; 74 int id1,id2; 75 it1 = c.find(s1); 76 if(it1 == c.end()) 77 { 78 c[s1] = ++ser; 79 strcpy(a[ser],s1.c_str()); 80 id1 = ser; 81 } 82 else 83 id1 = (*it1).second; 84 it2 = c.find(s2); 85 if(it2 == c.end()) 86 { 87 c[s2] = ++ser; 88 strcpy(a[ser],s2.c_str()); 89 id2 = ser; 90 } 91 else 92 id2 = (*it2).second; 93 edge[id1][id2] = 1; 94 } 95 } 96 void init3()//把能通过某插座让某设备工作的resi[u][v] =INF 97 { 98 queue<int>Q; 99 memset(qua,0,sizeof(qua)); 100 for(int i=0; i<=ser; ++i) 101 { 102 Q.push(i); 103 while(!Q.empty()) 104 { 105 int u = Q.back(); 106 Q.pop(); 107 for(int j=0; j<=ser; ++j) 108 { 109 if(edge[u][j] == 1) 110 { 111 Q.push(j); 112 reach[i][qua[i]++] = j; 113 } 114 } 115 } 116 } 117 for(int i=0; i<=ser; ++i) 118 { 119 string s = a[i]; 120 map<string,int>::iterator it1,it2; 121 it1 = mp.find(s); 122 if(it1 != mp.end()) 123 { 124 int u = (*it1).second; 125 for(int j=0; j<qua[i]; ++j) 126 { 127 string str = a[reach[i][j]]; 128 str = str+'d'; 129 it2 = mp.find(str); 130 if(it2 != mp.end()) 131 { 132 int v = (*it2).second; 133 resi[u][v] = INF; 134 } 135 } 136 } 137 } 138 for(int i=0; i<n; ++i) 139 resi[ss][i] = 1; 140 for(int i=n; i<=cur; ++i) 141 resi[i][tt] = num[i]; 142 } 143 void pushRelabel()//预流推进算法 144 { 145 queue<int>act; 146 int ef[MAXN],h[MAXN]; 147 int i; 148 int sum = 0; 149 int u,p; 150 memset(ef,0,sizeof(ef)); 151 memset(h,0,sizeof(h)); 152 h[ss] = cur+3; 153 ef[ss] = INF; 154 ef[tt] = -INF; 155 act.push(ss); 156 while(!act.empty()) 157 { 158 u =act.front(); 159 act.pop(); 160 for(i=0; i<=cur+2; ++i) 161 { 162 p = min(resi[u][i],ef[u]); 163 if(p>0 &&(u == ss || h[u] == h[i]+1)) 164 { 165 resi[u][i] -= p; 166 resi[i][u] += p; 167 ef[u] -= p; 168 ef[i] += p; 169 if(i == tt) 170 sum += p; 171 if(i != ss && i != tt) 172 act.push(i); 173 } 174 } 175 if(u != ss && u != tt && ef[u] >0) 176 { 177 ++h[u]; 178 act.push(u); 179 } 180 } 181 printf("%d\n",m-sum);//直接在这里输出结果 182 } 183 int main() 184 { 185 freopen("in.cpp","r",stdin); 186 init1(); 187 init2(); 188 init3(); 189 pushRelabel(); 190 return 0; 191 }
该代码在ZOJ上交超时,没办法,只得想办法优化,自我感觉也没有优化多少,ZOJ给10s我都超时,“优化”完后,100ms内 过了,不理解
ZOJ的代码:
View Code
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <string> 5 #include <map> 6 #include <queue> 7 using namespace std; 8 #define MAXN 400 9 #define INF 0x7fffffff 10 #define min(a,b) a<b?a:b 11 map<string,int>mp;//原插座转换器 12 map<string,int>dev; 13 bool edge[MAXN][MAXN];//原插座+转换器的邻接矩阵 14 int ss,tt;//源点和汇点 15 int n,m; 16 int cur,ser;//原插座+设备的数目 17 int resi[MAXN][MAXN]; //容量网络 18 char a[MAXN][30];//存转换器中的插头插座名字 19 void init1()//读入会议室提供的插座和设备所需插座 20 { 21 int i; 22 map<string,int>::iterator it; 23 memset(resi,0,sizeof(resi)); 24 scanf("%d",&n); 25 for(i=0; i<n; ++i) 26 { 27 cin>>a[i]; 28 mp[a[i]] = i; 29 } 30 ss = n; 31 tt = n+1; 32 scanf("%d",&m); 33 cur = n+1; 34 for(i=0; i<m; ++i) 35 { 36 string d,dname; 37 cin>>dname>>d; 38 it = dev.find(d); 39 if(it != dev.end()) 40 ++resi[(*it).second][tt]; 41 else 42 { 43 dev[d] = ++cur; 44 resi[cur][tt] = 1; 45 } 46 } 47 for(int i=0; i<n; ++i) 48 { 49 resi[ss][i] = 1; 50 string s = a[i]; 51 it = dev.find(s); 52 if(it != dev.end()) 53 resi[i][(*it).second] = INF; 54 } 55 } 56 void init2()//读入转换器的情况,构造出转换的邻接矩阵 57 { 58 int k; 59 map<string,int>::iterator it1,it2; 60 scanf("%d",&k); 61 memset(edge,0,sizeof(edge)); 62 ser = n-1; 63 while(k--) 64 { 65 string s1,s2; 66 cin>>s2>>s1; 67 int id1,id2; 68 it1 = mp.find(s1); 69 if(it1 == mp.end()) 70 { 71 mp[s1] = ++ser; 72 strcpy(a[ser],s1.c_str()); 73 id1 = ser; 74 } 75 else 76 id1 = (*it1).second; 77 it2 = mp.find(s2); 78 if(it2 == mp.end()) 79 { 80 mp[s2] = ++ser; 81 strcpy(a[ser],s2.c_str()); 82 id2 = ser; 83 } 84 else 85 id2 = (*it2).second; 86 edge[id1][id2] = 1; 87 } 88 } 89 void init3()//如果v设备插的插座可以由u转来,那么resi[u][v] = INF 90 { 91 queue<int>Q; 92 map<string,int>::iterator it; 93 for(int i=0; i<n; ++i) 94 { 95 Q.push(i); 96 while(!Q.empty()) 97 { 98 int u = Q.front(); 99 Q.pop(); 100 for(int j=0; j<=ser; ++j) 101 { 102 if(edge[u][j] == 1) 103 { 104 Q.push(j); 105 string s = a[j]; 106 it = dev.find(s); 107 if(it != dev.end()) 108 resi[i][(*it).second] = INF; 109 } 110 } 111 } 112 } 113 } 114 void pushRelabel() 115 { 116 queue<int>act; 117 int ef[MAXN],h[MAXN]; 118 int i; 119 int sum = 0; 120 int u,p; 121 memset(ef,0,sizeof(ef)); 122 memset(h,0,sizeof(h)); 123 h[ss] = cur+1; 124 ef[ss] = INF; 125 ef[tt] = -INF; 126 act.push(ss); 127 while(!act.empty()) 128 { 129 u =act.front(); 130 act.pop(); 131 for(i=0; i<=cur; ++i) 132 { 133 p = min(resi[u][i],ef[u]); 134 if(p>0 &&(u == ss || h[u] == h[i]+1)) 135 { 136 resi[u][i] -= p; 137 resi[i][u] += p; 138 ef[u] -= p; 139 ef[i] += p; 140 if(i == tt) 141 sum += p; 142 if(i != ss && i != tt) 143 act.push(i); 144 } 145 } 146 if(u != ss && u != tt && ef[u] >0) 147 { 148 ++h[u]; 149 act.push(u); 150 } 151 } 152 printf("%d\n",m-sum); 153 } 154 int main() 155 { 156 // freopen("in.cpp","r",stdin); 157 int T; 158 scanf("%d",&T); 159 while(T--) 160 { 161 mp.clear(); 162 dev.clear(); 163 init1(); 164 init2(); 165 init3(); 166 pushRelabel(); 167 if(T != 0) 168 puts(""); 169 } 170 return 0; 171 }
代码的长度也有所减少啊