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



 

發佈了88 篇原創文章 · 獲贊 2 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章