SGU145 Strange People 严格K短路

严格的意思是每个节点只允许访问一次。

解法:二分k短路路长。

注意点: 观察数据范围,应该是稠密图,比较适合矩阵,测了一下矩阵比邻接表快100+ms。 另外可以先做一次spfa预处理,利用节点到t的距离剪枝,这能从300+ms优化到31ms。 

TLE点:我之前二分的时候,每次是求出满足要求的路径个数,TLE 3。  看了别人代码发现每次只要找到K条路径就行,看下数据,k<=500,这样时间优化的还是挺多的...(对数据范围还是不敏感啊,只知道yy,不知道看数据范围T_T...)

矩阵+spfa优化 31ms

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
#define INF 0x7ffffff
int e[105][105],n,m,s,t,k,limit;
bool visited[105];
int path[105],pcnt,cnt,dist[105];
bool inq[105];
bool flag;
void spfa()
{
    int i,u,v,d;
    for(i=1;i<=n;++i)
        dist[i]=INF;
    memset(inq,false,sizeof(inq));
    dist[t]=0;inq[t]=true;
    deque<int> q;
    q.push_front(t);
    while(!q.empty())
    {
        u=q.front();inq[u]=false;q.pop_front();
        for(i=1;i<=n;++i)
        {
            if(e[u][i]!=0)
            {
                d=e[u][i];v=i;
                if(dist[u]+d<dist[v])
                {
                    dist[v]=dist[u]+d;
                    if(!inq[v])
                    {
                        inq[v]=true;
                        if(!q.empty()&&dist[v]<=dist[q.front()])
                            q.push_front(v);
                        else
                            q.push_back(v);
                    }
                }
            }
        }
    }
}
void dfs(int u,int sum)
{
    visited[u]=true;
    if(u==t)
    {
        if(sum<=limit)
            cnt++;
        if(cnt>=k)
            flag=true;
        visited[u]=false;
        return ;
    }
    int v,i,d;
    if(sum+dist[u]>limit)
    {
        visited[u]=false;
        return ;
    }
    for(i=1;i<=n;++i)
    {
        if(e[u][i]!=0&&!visited[i])
        {
            d=e[u][i];
            if(sum+d<=limit)
                dfs(i,sum+d);
            if(flag)
            {
                visited[u]=false;
                return ;
            }
        }
    }
    visited[u]=false;
    return ;
}
void find_path(int u,int sum)
{
    visited[u]=true;path[pcnt++]=u;
    if(u==t)
    {
        if(sum==limit)
        {
            printf("%d %d\n",limit,pcnt);
            for(int i=0;i<pcnt;++i)
                printf("%d%c",path[i],i==pcnt-1?'\n':' ');
            visited[u]=false;pcnt--;
            flag=true;
            return ;
        }
        else
        {
            visited[u]=false;pcnt--;
            return ;
        }
    }
    int i,d;
    if(sum+dist[u]>limit)
    {
        visited[u]=false;pcnt--;
        return ;
    }
    for(i=1;i<=n;++i)
    {
        if(e[u][i]!=0&&!visited[i])
        {
            d=e[u][i];
            if(sum+d<=limit)
                find_path(i,sum+d);
            if(flag)
            {
                visited[u]=false;
                pcnt--;
                return ;
            }
        }
    }
    visited[u]=false;pcnt--;
    return ;
}
int main()
{
    int i,u,v,cost,l,r=0,mid;
    memset(e,0,sizeof(e));
    memset(visited,false,sizeof(visited));
    pcnt=0,cnt=0;
    scanf("%d %d %d",&n,&m,&k);
    for(i=0;i<m;++i)
    {
        scanf("%d %d %d",&u,&v,&cost);
        e[u][v]=e[v][u]=cost;
        r+=cost;
    }
    scanf("%d %d",&s,&t);
    spfa();
    l=0;
    while(l!=r)
    {
        mid=(l+r)>>1;
        limit=mid;
        cnt=0,flag=false;
        dfs(s,0);
        if(!flag)
        {
            l=mid+1;
        }
        else
        {
            r=mid;
        }
    }
    limit=l,flag=false;
    find_path(s,0);
    return 0;
}

邻接表 无优化 479ms。。。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
#define INF 0x7ffffff
struct edge
{
    int to,w,next;
}ee[10010];
int e[105],ecnt,s,t,k,limit,n,m;
bool visited[105];
int path[105],pcnt,cnt;
bool flag;
void addedge(int u,int v,int cost)
{
    ee[ecnt].to=v;ee[ecnt].w=cost;ee[ecnt].next=e[u];e[u]=ecnt;
    ecnt++;
    ee[ecnt].to=u;ee[ecnt].w=cost;ee[ecnt].next=e[v];e[v]=ecnt;
    ecnt++;
}
void dfs(int u,int sum)
{
    if(u==t)
    {
        if(sum<=limit)
        {
            cnt++;
            if(cnt>=k)
                flag=true;
            return ;
        }
        else
            return ;
    }
    visited[u]=true;
    int pt,v,d;
    for(pt=e[u];pt!=-1;pt=ee[pt].next)
    {
        v=ee[pt].to;d=ee[pt].w;
        if(!visited[v])
        {
            if(sum+d<=limit)
                dfs(v,sum+d);
            if(flag)
            {
                visited[u]=false;
                return ;
            }
        }
    }
    visited[u]=false;
    return ;
}
bool find_path(int u,int sum)
{
    path[pcnt++]=u;
    visited[u]=true;
    if(u==t)
    {
        if(sum==limit)
        {
            printf("%d %d\n",limit,pcnt);
            for(int i=0;i<pcnt;++i)
                printf("%d%c",path[i],i==pcnt-1?'\n':' ');
            pcnt--;
            visited[u]=false;
            return true;
        }
        else
        {
            visited[u]=false;pcnt--;
            return false;
        }
    }
    int pt,v,d;
    for(pt=e[u];pt!=-1;pt=ee[pt].next)
    {
        v=ee[pt].to;d=ee[pt].w;
        if(!visited[v])
        {
            if(sum+d<=limit)
            {
                if(find_path(v,sum+d)==true)
                {
                    pcnt--;
                    visited[u]=false;
                    return true;
                }
            }
        }
    }
    visited[u]=false;pcnt--;
    return false;
}
int main()
{
    int i,u,v,cost;
    int l,r,mid,tt;
    r=0;
    scanf("%d %d %d",&n,&m,&k);
    memset(e,-1,sizeof(e));
    ecnt=0;
    for(i=0;i<m;++i)
    {
        scanf("%d %d %d",&u,&v,&cost);
        addedge(u,v,cost);
        r+=cost;
    }
    scanf("%d %d",&s,&t);
    l=0;
    while(l!=r)
    {
        mid=(l+r)>>1;
        limit=mid;
        memset(visited,false,sizeof(visited));
        flag=false,cnt=0;
        dfs(s,0);
//        printf("limit==%d,ans==%d\n",limit,flag);
        if(!flag)
        {
            l=mid+1;
        }
        else
        {
            r=mid;
        }
    }
    limit=l;
    memset(visited,false,sizeof(visited));
    pcnt=0;
    find_path(s,0);
    return 0;
}



 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值