Senior Pan
Problem Description
Senior Pan fails in his discrete math exam again. So he asks Master ZKC to give him graph theory problems everyday.
The task is simple : ZKC will give Pan a directed graph every time, and selects some nodes from that graph, you can calculate the minimum distance of every pair of nodes chosen in these nodes and now ZKC only cares about the minimum among them. That is still too hard for poor Pan, so he asks you for help.
The task is simple : ZKC will give Pan a directed graph every time, and selects some nodes from that graph, you can calculate the minimum distance of every pair of nodes chosen in these nodes and now ZKC only cares about the minimum among them. That is still too hard for poor Pan, so he asks you for help.
Input
The first line contains one integer T, represents the number of Test Cases.1≤T≤5.Then T Test Cases, for each Test Cases, the first line contains two integers n,m representing the number of nodes and the number of edges.1≤n,m≤100000
Then m lines follow. Each line contains three integers xi,yi representing an edge, and vi representing its length.1≤ xi,yi ≤n,1≤ vi ≤100000
Then one line contains one integer K, the number of nodes that Master Dong selects out.1≤K≤n
The following line contains K unique integers ai , the nodes that Master Dong selects out.1≤ ai ≤n, ai !=aj
Then m lines follow. Each line contains three integers xi,yi representing an edge, and vi representing its length.1≤ xi,yi ≤n,1≤ vi ≤100000
Then one line contains one integer K, the number of nodes that Master Dong selects out.1≤K≤n
The following line contains K unique integers ai , the nodes that Master Dong selects out.1≤ ai ≤n, ai !=aj
Output
For every Test Case, output one integer: the answer
Sample Input
1 5 6 1 2 1 2 3 3 3 1 3 2 5 1 2 4 2 4 3 1 3 1 3 5
Sample Output
Case #1: 2
Source
题意:T组测试数据,n个顶点,m条边,挑出k个顶点,求这k个顶点之间的最短距离。
分析:很巧妙的一道题。如果直接枚举这k个顶点的最短路,肯定会超时。但是我们可以很快得出一个结论,这k个点中的最优解,必然有一个是起点,一个是终点,然后我们可以枚举起点集合和终点集合,这里起点和终点集合可以通过某二进制位的0和1来划分,最多有20位二进制位,这样必然会将所有的起点和终点涵盖,增加一个超级源点和超级汇点,超级源点连接起点集合的所有点,超级汇点连接终点集合的所有点,接下来就是跑SPFA,取到超级汇点的最小值。听说还有随机分组的写法,欢迎路过的大佬指导。
AC代码:
随便加个输入挂,时间2000ms左右,写法还是弱.。。QAQ
#include<bits/stdc++.h>
using namespace std;
struct Edge{
int v,next;
int w;
};
int head[100005];
Edge edge[200005];
int cnt;
int to_binary[100005][20];
int a[100005];
int temp_head[100005];
namespace fastIO
{
#define BUF_SIZE 200005
bool IOerror=0;
inline char nc()
{
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if(p1==pend)
{
p1=buf;
pend=buf+fread(buf,1,BUF_SIZE,stdin);
if(pend==p1)
{
IOerror=1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch)
{
return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
}
inline void read(int &x)
{
char ch;
while(blank(ch=nc()));
if(IOerror)
return ;
for(x=ch-'0'; (ch=nc())>='0'&&ch<='9'; x=x*10+ch-'0');
}
#undef BUF_SIZE
};
void add(int u,int v,int w){
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
int s,t;
int id[100005];
int d[100005];
int SPFA(){
memset(id,0,sizeof(id));
memset(d,0x3f3f3f3f,sizeof(d));
d[0]=0;
queue<int> q;
q.push(0);
id[0]++;
while(q.empty()==0){//
int u=q.front();
q.pop();
id[u]--;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
int w=edge[i].w;
if(d[u]+w<d[v]){
d[v]=d[u]+w;
if(id[v]==0){
id[v]++;
q.push(v);
}
}
}
}//printf("end----------%d\n",d[t]);
return d[t];
}
int main(){
int N;
fastIO::read(N);
//scanf("%d",&N);
for(int cas=1;cas<=N;cas++){
memset(to_binary,0,sizeof(to_binary));
memset(head,-1,sizeof(head));
cnt=0;
int n,m;
//scanf("%d%d",&n,&m);
fastIO::read(n);
fastIO::read(m);
for(int i=1;i<=m;i++){
int u,v;
int w;
fastIO::read(u);
fastIO::read(v);
fastIO::read(w);
//scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
for(int i=0;i<=n+1;i++){
temp_head[i]=head[i];
}
int k;
fastIO::read(k);
//scanf("%d",&k);
for(int i=1;i<=k;i++){
int u;
fastIO::read(u);
//scanf("%d",&u);
a[i]=u;
int record[20];
int num=0;
while(u){
to_binary[i][num++]=u%2;
u/=2;
}
}
s=0;
t=n+1;
int ans=0x3f3f3f3f;
for(int sign=0;sign<=1;sign++){
for(int i=0;i<20;i++){
//printf("%d------------>",i);
for(int j=1;j<=k;j++){
if(to_binary[j][i]==sign){
add(s,a[j],0);
}
else{
add(a[j],t,0);
}
}
ans=min(ans,SPFA());
cnt-=k;
head[s]=-1;
head[t]=-1;
for(int j=1;j<=k;j++){
head[a[j]]=temp_head[a[j]];
}
}
}
printf("Case #%d: %d\n",cas,ans);
}
return 0;
}