2016年1月25日 星期一

[ZJ a764]pC. Tony 與只有神知道的世界

先備知識:Dijkstra

此題就是要你找出最小的環($\geq$三點)
可以發現,只要不走回頭路,走回原點時一定會經過三點以上,因此只要以每個點當原點做Dijkstra,狀態中紀錄上一個走過的點,走回原點之際回傳更新答案就好

時間複雜度:$O(N^{3}\log N)$

p.s.如果狀態用三個int(現在的點、上一個點、走過的距離)存會在最後一筆MLE,我把現在的點和上一個點合起來用一個int存就過了=ㄦ=

code:
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int INF=2147483647;
void getmin(int &a,const int b){if(b<a)a=b;}
struct Edge
{
    int a,b,cost;
    Edge(){}
    Edge(const int _a,const int _b,const int _c):a(_a),b(_b),cost(_c){}
};
int N,M;
bool VIS[400][400];
vector<int>ET[400];
vector<Edge>EDGE;
struct Pq
{
    int u,cost;
    Pq(){}
    Pq(const int _u,const int _p,const int _c):u(_u*N+_p),cost(_c){}
    bool operator<(const Pq &p)const{return cost>p.cost;}
};
int Solve(const int source)
{
    for(int i=0;i<N;i++)for(int j=0;j<N;j++)VIS[i][j]=false;
    priority_queue<Pq>pq;
    for(const int ei:ET[source])
    {
        const Edge &e=EDGE[ei];
        const int nxt=(e.a==source?e.b:e.a);
        pq.push(Pq(nxt,source,e.cost));
    }
    while(!pq.empty())
    {
        const Pq p=pq.top();pq.pop();
        const int u=p.u/N,pre=p.u%N;
        if(VIS[u][pre])continue;
        VIS[u][pre]=true;
        if(u==source)return p.cost;
        for(const int ei:ET[u])
        {
            const Edge &e=EDGE[ei];
            const int nxt=(e.a==u?e.b:e.a);
            if(nxt==pre)continue;
            pq.push(Pq(nxt,u,p.cost+e.cost));
        }
    }
    return INF;
}
int main()
{
    scanf("%d%d",&N,&M);
    for(int i=0;i<N;i++)ET[i].clear();
    EDGE.clear();
    for(int i=0,a,b,c;i<M;i++)
    {
        scanf("%d%d%d",&a,&b,&c),a--,b--;
        if(a==b){M--,i--;continue;}
        EDGE.push_back(Edge(a,b,c));
        ET[a].push_back(i),ET[b].push_back(i);
    }
    int ans=INF;
    for(int i=0;i<N;i++)getmin(ans,Solve(i));
    if(ans==INF)puts("No solution.");
    else printf("%d\n",ans);
    return 0;
}

沒有留言:

張貼留言

歡迎留言或問問題~
若您的留言中包含程式碼,請參考這篇
如果留言不見了請別慌,那是因為被google誤判成垃圾留言,小莫會盡快將其手動還原