HDU 6166 Senior Pan(SPFA+二进制分组)

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.
 

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
 

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;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值