1. 程式人生 > >D1圖論最短路專題

D1圖論最短路專題

一個 經典 sstream tps mina oid cst 圖片 void

第一題:poj3660

其實是Floyed算法的拓展:Floyd-Wareshall。初始時,若兩頭牛關系確定則fij = 1。 對於一頭牛若確定的關系=n-1,這說明這頭牛的排名是確定的。

通過尋找節點k來判斷;

技術分享圖片
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include
<cstdlib> #include<cstring> #include<ctime> #include<deque> #include<exception> #include<fstream> #include<functional> #include<limits> #include<list> #include<map> #include<iomanip> #include<ios> #include<iosfwd> #include
<iostream> #include<istream> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<utility> #include<vector> #include<cwchar> #include
<cwctype> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) {if(ch==- ) f=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,m,x,y,f[5100][5100],ans,tot; void floyed() { for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=f[i][j]|f[i][k]&f[k][j]; } int main() { n=read();m=read(); for(int i=1;i<=m;i++) { x=read();y=read(); f[x][y]=1; } floyed(); for(int i=1;i<=n;i++) { int ans=0; for(int j=1;j<=n;j++) { if(f[i][j]||f[j][i]) ++ans; } if(ans==n-1) ++tot; }cout<<tot; return 0; }
View Code

第二題:UVA11374枚舉(還沒寫,會補上);

第三題:bzoj4152 考慮建邊,如果暴力建邊則需要建n2條邊,顯然不可接受。

可以分析一下邊權的性質:對於(x1, y1),(x2, y2),(x3, y3)這三個點 若x1 ≤ x2 ≤ x3,(即相鄰)則從x方向由P1? > P3的邊可以 由(P1? > P2) + (P2? > P3)組成,所以P1? > P3的邊可以不用顯式的 建出來,而是由P1? > P2 和P2? > P3 的邊構成。 註意:本題最短路算法卡SPFA。(我寫過一篇這個題解,可參考)

技術分享圖片
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
#define inf 0x3f
using namespace std;
#define pii pair<int,int>
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch==-) f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;    
}
struct pink
{
    int x,y,id;
}h[201000];
struct gg
{
    int y,next,v;
}a[200000<<2];
bool mycmp1(pink a,pink b)
{
    return a.x<b.x;
}
bool mycmp2(pink s,pink m)
{
    return s.y<m.y;
}
int lin[201000],n,m,tot;
bool vis[201000];
long long dis[201000];
inline void init(int x,int y,int z)
{
    a[++tot].y=y;
    a[tot].v=z;
    a[tot].next=lin[x];
    lin[x]=tot;    
}
/*void dijkstra(int s)
{
    priority_queue<pii,vector<pii>,greater<pii> >q;
    for(int i=1;i<=n;i++)
        dis[i]=inf*(i!=s);
    q.push(pii(dis[s],s));
    while(!q.empty())
    {
        pii now=q.top();q.pop();
        int u=now.second;
//        cout<<")"<<u<<endl;system("pause");
        if(dis[u]<now.first)    continue;
        for(int i=lin[u];i;i=a[i].next)
        {
            int v=a[i].y;
            if(dis[v]>dis[u]+a[i].v)
            {
                dis[v]=dis[u]+a[i].v;
                q.push(pii(dis[v],v));
            }        
        }
    }
}*/
inline void dijkstra_heap(int s)
{
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    priority_queue<pii,vector<pii>,greater<pii> >q;
    dis[s]=0;
    q.push(make_pair(0,s));
    while (!q.empty())
    {
        int x=q.top().second;
        q.pop();
        if (vis[x]) continue;
        vis[x]=1;
        for (int i=lin[x];i;i=a[i].next)
        {
            int y=a[i].y;
            if (dis[y]>dis[x]+a[i].v)
            {
                dis[y]=dis[x]+a[i].v; 
                q.push(make_pair(dis[y],y));
            }
        }
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        h[i].id=i,h[i].x=read(),h[i].y=read();
    sort(h+1,h+n+1,mycmp1);
    for(int i=1;i<n;i++)
        init(h[i].id,h[i+1].id,abs(h[i].x-h[i+1].x)),init(h[i+1].id,h[i].id,abs(h[i].x-h[i+1].x));
    sort(h+1,h+n+1,mycmp2);
    for(int i=1;i<n;i++)
        init(h[i].id,h[i+1].id,abs(h[i].y-h[i+1].y)),init(h[i+1].id,h[i].id,abs(h[i].y-h[i+1].y));
    dijkstra_heap(1);
    cout<<dis[n]<<endl;
    return 0; 
}
View Code

第四題:UVA10603 不會寫對不起;

第五題:HYSBZ2662;主要是運用一個分層圖的思想,註意到k是比較小的,所以我們可以把k強行拆開,把一個點分為k個,分別表示用k張卡片所走的最短路,我們可以理解為走了k個圖,相鄰圖之間的路變為原來所走的路的一半,所以這樣建圖:各層內部正常連邊,各層之間權值為一半的邊。每跑一層,就相當於使用一次卡片。跑一遍從s到t+n*k的最短路即可,第i層和第i+1層之間路權值變為原來的一半;相當於用了一次卡,這裏我用了dijkstra的堆優化(多練習一下剛學會),spfa也可以過;

技術分享圖片
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
int h,n,m,k,s,t,a,b,c,tot,lin[220009];
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch==-) f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
struct edge
{
    int y,v,next;
}an[4200009];
int dis[220009];
bool vis[220009];
typedef pair <int,int> pii;
priority_queue <pii,vector<pii>,greater<pii> > q;
void add(int x,int y,int z)
{
    an[++tot].y=y;
    an[tot].v=z;
    an[tot].next=lin[x];
    lin[x]=tot;
}
void diskstra_heap(int s)
{
    memset(dis,127,sizeof(dis));
    dis[s]=0;
    q.push(make_pair(dis[s],s));
    int x,j;
    while (q.size())
    {
        x=q.top().second;
        q.pop();
        if(vis[x]) continue;
        vis[x]=true;
        for (int i=lin[x];i;i=an[i].next)
        {
            j=an[i].y;
            if(dis[x]+an[i].v>=dis[j]) continue;
            dis[j]=dis[x]+an[i].v;
            q.push(make_pair(dis[j],j));
        }
    }
}

int main()
{
    n=read();m=read();k=read();
    for (int i=1;i<=m;++i)
    {
        a=read();b=read();c=read();
        add(a,b,c);
        add(b,a,c);
        for (int j=1;j<=k;++j)
        {
            add(j*n+a,j*n+b,c);
            add(j*n+b,j*n+a,c);
            add((j-1)*n+a,j*n+b,c/2);
            add((j-1)*n+b,j*n+a,c/2);
        }
    }  
    s=1,t=n;//從1到n的路徑
    diskstra_heap(s);
    int ans=dis[t];
    for(int i=0;i<=k;++i)
        ans=min(ans,dis[i*n+t]);
    cout<<ans;
    return 0;
}
View Code

第六題:數論建圖:luoguP2371;(重點強調神仙題)

這個題拿到題面,數學題?推結論 ?後來發現很明顯不能寫,如果直接尋找x的結果,可想。。。不可做;

後來學長一句話:無限背包跑最短路。wow什麽,沒聽說過;

上課ppt的題解:題目可以理解成經典的背包問題。只是他問你的是[Bmin, Bmax ]區間 中有多少個容積是恰好可以裝滿的。範圍很大,傳統的暴力是行不通 的。 首先取出最小的ai,設為p。那麽考慮令d[i]表示當物體的總 重mod p = i時,物體最少的重量。設d[i] = t,那麽顯然對於所有的x, 如果x mod p = i且t ≤ x,都可以用總重最少的那個方案再加上若幹個p 到。 同時,考慮加入一個物體u,那麽顯然有d[(i + u) mod p]可以 由d[i] + u得到,這不就是兩點間連邊嗎?d[i]求最小值不就是最短路 嗎? 方案數轉化為了最短路問題。(理解了好久覺得挺對)

另外:我們可以用數論的思想來轉向圖論思考;我們在這些數列an裏任取一個ai,表示為k,那 麽這個B%k肯定是在0–k-1之間的,如果一個B滿足條件,B%k=d, 那麽(B+k)%k也肯定為d,那其實就是說,只要我們能找到,B%k=d的, 且滿足條件的最小的B,在一直往上加k,直到加到最大上屆為止,並統計個數,(這些B都是符合條件的), 就得到了B%k=d所有的可能,在枚舉不同的d,累加起來;

我們要d盡可能的小,就要k盡可能的小,所以我們對數列進行排序,取最小的ai,那麽當前我們能尋找到最小的B;(有些題解說是同余最短路);

技術分享圖片
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
#define inf 0x3f3f3f3f3f3f3f3fll
using namespace std;
inline long long read()
{
    long long x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch==- ) f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
 }
long long dis[500005],vis[500005],tot,n,l,r;
long long mina,minb,minv=inf,a[1000];
void spfa()
{
     memset(dis,0x3f,sizeof(dis));
     memset(vis,0,sizeof(vis));
     queue<int>q;
     dis[0]=0;vis[0]=1;
     q.push(0);
     while(q.size())
     {
         int x=q.front();q.pop();vis[x]=0;
         for(int i=1;i<=n;i++)
         {
             int y=(x+a[i])%minv;
             if(dis[y]>dis[x]+a[i])
             {
                 dis[y]=dis[x]+a[i];
                if(!vis[y]) vis[y]=1,q.push(y);    
            }
        }
    }
 }
long long query(long long x)
 {
     long long ans=0;
     for(int i=0;i<minv;i++)
     {
         if(dis[i]<=x) 
            ans+=(x-dis[i])/minv+1;    
    }
    return ans;
 }
 int main()
 {
     n=read();l=read();r=read();
     for(int i=1;i<=n;i++)
     {
         a[i]=read();
        if(!a[i])i--,n--;
        minv=min(minv,a[i]); 
    }
    spfa();
    cout<<query(r)-query(l-1);
    return 0;
 }
View Code

D1圖論最短路專題