HDU 6166 二进制划分集合

首先这个题化成两个集合还是很容易的想到的,但是不知道怎么用二进制表示,感觉这个题的脑洞还是很大的。

为什么可以用二进制表示化成集合可以包含所有的点对,因为要是两个数不同的话肯定会有一个二进制的位数不同

所以就包含了所有的点对。

 

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
const int N=5e5;
struct node
{
    int u,v;
    long long w;
}s[N];
int node[N],nxt[N],head[N];
int n,m,tot,begins,vis[N];
long long d[N],data[N];
void add(int x,int y,long long z)
{
    node[++tot]=y;nxt[tot]=head[x];head[x]=tot;data[tot]=z;
}
void inist()
{
    //memset(vis,0,sizeof(vis));
    tot=0;
    memset(node,0,sizeof(node));
    memset(head,0,sizeof(head));
    memset(data,0,sizeof(data));
}
void Dij()
{
    for(int i=1;i<=n+2;i++) d[i]=10000000000000LL;
    d[begins]=0;
    priority_queue<pair<long long,long long> > heap;
    heap.push(make_pair(-d[begins],begins));
    while (1){
        for (;!heap.empty() && -d[heap.top().second]!=heap.top().first;heap.pop());
        if (heap.empty()) break;

        int now=heap.top().second;
        heap.pop();

        for (int i=head[now];i;i=nxt[i]){
            int j=node[i];
            if (d[j]>d[now]+data[i]){
                d[j]=d[now]+data[i];
                heap.push(make_pair(-d[j],j));
            }
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    int id=0;
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        id++;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%lld",&s[i].u,&s[i].v,&s[i].w);
        }
        int k;
        scanf("%d",&k);
        for(int i=1;i<=k;i++)
        {
            int x;
            scanf("%d",&x);
            vis[x]=1;
        }
        int num=1;
        long long ans=100000000000000LL;
        while(num!=20)
        {
            inist();
            for(int i=1;i<=m;i++)
            {
                int u=s[i].u,v=s[i].v;
                if(vis[u])
                {
                    if(u&(1<<(num-1)))
                    {
                        u=n+1;
                    }
                    else u=n+2;
                }
                if(vis[v])
                {
                    if(v&(1<<(num-1)))
                    {
                        v=n+1;
                    }
                    else v=n+2;
                }
                add(u,v,s[i].w);
            }
            //begins=n+1;
           // Dij();
            //ans=min(ans,d[n+2]);
            begins=n+2;
            Dij();
            ans=min(ans,d[n+1]);
            num++;
        }
        printf("Case #%d: ",id);
        printf("%lld\n",ans);
    }
}

 

posted @ 2017-08-26 10:46  Heilce  阅读(386)  评论(0编辑  收藏  举报