思路:实际上就是暴搜。先以面之间是否直连构图(注意flag的应用)。然后枚举每个club点,算其与所有面的最短距离,实际上就是权值都为1的最短路,bfs即可(必须穿过的边数)。最后扫一遍r个区域求最小值即可。这样做的复杂度是O(nr)。(其他人有的做法是通过上面构图求Floyd最短路,然后再找没有必要)。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 255 #define R 205 int c[35],g[R][R],flag[N][N],dis[35][R],adj[N][R],used[R]; int r,n,l; void bfs(int j){ int i,now,front,rear,q[N],x; x = c[j]; front = rear = -1; memset(used, 0, sizeof(used)); for(i = 1;i<=r;i++) if(adj[x][i]){ dis[j][i] = 0; used[i] = 1; q[++rear] = i; } while(front < rear){ now = q[++front]; for(i = 1;i<=r;i++) if(g[now][i] && !used[i]){ used[i] = 1; q[++rear] = i; dis[j][i] = dis[j][now]+1; } } } int main(){ int i,j,num,a,b=0,tmp,res=0x3fffffff; memset(flag, 0, sizeof(flag)); memset(dis, 0, sizeof(dis)); memset(adj, 0, sizeof(adj)); memset(g, 0, sizeof(g)); scanf("%d %d %d",&r,&n,&l); for(i = 1;i<=l;i++) scanf("%d",&c[i]); for(i = 1;i<=r;i++){ scanf("%d",&num); scanf("%d",&a); adj[a][i] = 1; tmp = a; for(j = 1;j<num;j++){ scanf("%d",&b); adj[b][i] = 1; if(!flag[a][b]) flag[a][b] = flag[b][a] = i; else g[i][flag[a][b]] = g[flag[a][b]][i] = 1; a = b; } if(num>=3){ if(!flag[tmp][b]) flag[tmp][b] = flag[b][tmp] = i; else g[i][flag[tmp][b]] = g[flag[tmp][b]][i] = 1; } } for(i = 1;i<=l;i++) bfs(i); for(i = 1;i<=r;i++){ for(j = 1,tmp = 0;j<=l;j++) tmp += dis[j][i]; res = min(res,tmp); } printf("%d\n",res); return 0; }