Processing math: 0%

2015年7月20日 星期一

[HOJ 199] KAMPANJA

作法:

考慮d[A][B]代表從1走到A走到B再走回A的路上最少可以經過幾個節點,那麼所求的答案就是d[2][2]。首先我們可以用 Floyd 求出任兩點之間的最短路(之後記為dis[][]),就可以先得到d[A][B]的一些初始值,並且由第一個範測可以觀察到:如果我們任取四個點A,B,X,Y,那麼1\rightarrow X\rightarrow Y\rightarrow 1實際上可以用1\rightarrow  A\rightarrow  B\rightarrow  X\rightarrow  Y\rightarrow  A\rightarrow  B\rightarrow  1來達成,也就是我們可以用d[A][B]+dis[B][X]+dis[X][Y]+dis[Y][A]-1來更新d[X][Y]的值。注意到上式中當X,Y,A,B不全相等時,dis[B][X]+dis[X][Y]+dis[Y][A]-1\geq 0,這就類似在求最短路的過程,因此我們可以直接套用 Dijkstra 求得答案。注意到這裡的 Dijkstra 不是用 priority_queue 優化的,而是優化前的「每次掃一遍所有的節點看誰目前距離最小,拿他來鬆弛其他人」,前者複雜度會變成O(n^4logn),後者則是O(n^4)(因為這張圖是稠密圖)。

code :



#include<bits/stdc++.h>
#define INF 1000
using namespace std;
const int maxn=100+5 ;
 
int dis[maxn][maxn] ;
int d[maxn][maxn] ;
bool done[maxn][maxn] ;
main()
{
    int n,m ; scanf("%d%d",&n,&m) ;
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
        dis[i][j]=(i==j?0:INF) ;
    while(m--)
    {
        int x,y ; scanf("%d%d",&x,&y) ;
        dis[x][y]=1 ;
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
        dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]) ;
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
        d[i][j]=min(INF,dis[1][i]+dis[i][j]+dis[j][1]) ;
    d[1][1]=1 ;
    int tot=n*n ;
    while(tot--)
    {
        int ix,iy,mi=INF+1 ;
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
            if(!done[i][j] && d[i][j]<mi)
            mi=d[i][j] , ix=i , iy=j ;
        done[ix][iy]=1 ;
        if(ix==2 && iy==2){printf("%d\n",mi) ; break ;}
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(!done[i][j])
            d[i][j]=min(d[i][j],d[ix][iy]+dis[iy][i]+dis[i][j]+dis[j][ix]-1) ;
    }
}
 

沒有留言:

張貼留言