bnu Treasure Diving

http://www.bnuoj.com/contest/problem_show.php?pid=26305

题意:给一个无向图,现选定图中的k(k<=8)个点,如果最多能走tot米,问最多能经过几个点(要求回到原点)。
思路:
暴力出k个点之间的最短距离,剩下k个点还是暴力弄。
但这样还是超时了,注意到tot最多只是1000000,因为要回到原点,所以距离大于tot的肯定不满足。
View Code
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 10005;
const int inf = 100000000;
struct nd{
    int v,next,c;
}as[maxn*10];
int ecnt,head[maxn];
int dis[maxn],vis[maxn];
int lis[12];
int n,m,tot,k;
int cs[12][12];
int bj[12];
int mx,ct,f;
void add(int a,int b,int c)
{
    as[ecnt].v = b;
    as[ecnt].c = c;
    as[ecnt].next = head[a];
    head[a] = ecnt++;
}
void spfa(int s,int idx)
{
    int i,u,v,c;
    for(i = 0; i < n; ++ i)
        dis[i]=inf,vis[i]=0;
    queue<int>que;
    que.push(s);
    dis[s]=0;
    while(!que.empty()){
        u = que.front(); que.pop();
        vis[u]=0;
        for(i = head[u]; i!=-1; i=as[i].next){
            v = as[i].v;
            c = as[i].c;
            if(dis[u]+c>=tot)continue;//这个剪枝很重要
            if(dis[v]>dis[u]+c){
                dis[v]=dis[u]+c;
                if(!vis[v]){
                    que.push(v);
                    vis[v]=1;
                }
            }
        }
    }
    for(i = 0; i < k; ++ i){
        if(cs[idx][i]>dis[lis[i]])
            cs[idx][i]=dis[lis[i]];
    }
}
void readin()
{
    int i,j;
    scanf("%d %d",&n,&m);
    for(i=0;i<n;++i)head[i]=-1;
    ecnt = 0;
    for(i = 0; i < m; ++ i){
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
    scanf("%d",&k);
    for(i = 0; i < k; ++ i)
        scanf("%d",lis+i);
    scanf("%d",&tot);
    if(!k)return;
    sort(lis,lis+k);
    f = 0;
    if(lis[0])lis[k++]=0;
    else f = 1;
    sort(lis,lis+k);
    
    for(i = 0; i < 12; ++ i)
        for(j = 0; j < 12; ++ j)
            if(i^j)cs[i][j]=inf;
            else cs[i][j]=0;
    for(i = 0; i < k; ++ i)
        spfa(lis[i],i);
}
void ts(int kk,int tt,int ss)
{
    if(mx<tt) mx=tt;
    if(tt==(k-1)||ct) { ct=1;return;}
    for(int i=1;i<k;i++)
    if(bj[i]==0&&ss>=(cs[0][i]+cs[kk][i]))
    {
        bj[i]=1;
        ts(i,tt+1,ss-cs[kk][i]);
        bj[i]=0;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        readin();
        mx=0;ct=0;
        if(k){
            memset(bj,0,sizeof(bj));
            ts(0,0,tot);
        }
        printf("%d\n",mx+f);
    }
    return 0;
}

 

posted on 2012-10-04 11:00  aigoruan  阅读(207)  评论(0)    收藏  举报

导航