atcoder reguler contest 089 E graph xy

構造一個滿足下列條件的有向圖:
1. 頂點數不超過 300 ,其中有一個源點 S 和一個匯點 T
2. 沒有重邊和自環
3. 頂點由 1N 編號
4. 每條邊的權值 [0,100] ,也可以是一個標籤 XY
5. 對於給定的每一對滿足 x[1,A],y[1,B](x,y) ,在標籤爲 X 的邊的權值爲 x ,標籤 Y 的權值爲 y 時,源點 S 到匯點 T 的最短路徑長度爲 d(x,y)

1A,B10
1d(x,y)100


每一條最短路都經過了一些 X 邊,一些 Y 邊和一些常數邊。我們發現如果有兩條 ST 的路徑包含了相同多的 X 邊和 Y 邊,常數邊大的那條邊是沒有意義的,因爲對於所有 (x,y) ,常數項小的那條路徑的權值肯定比常數項大的小。

d(i,j)100 ,所以我們可以按如下方式構圖:
這裏寫圖片描述

下半部分頂點可以自由向上半部分連常數權值的邊。
我們設 f(i,j) 代表過了 iX 邊, jY 邊的常數邊的權值,例如 f(1,2) 就代表了圖中 1 號點與 102 號點之間常數邊的權值。

那麼,

d(i,j)=min{ f(a,b)+ai+bj }

因爲我們要確定 f(a,b) 的值,所以我們反過來考慮
f(a,b)d(i,j)aibj,  iA,jB

我們讓每一個 f(a,b) 都儘量小,這樣就給最小的 d(i,j) 提供了一條最短路。

確定每個f(a,b) 的值後,我們只需要驗證一下是否符合即可。

O(d(i,j)2AB)

code:

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 350;
    const int INF = 1<<30;

    int a, b, s, t, sum, d[N][N], f[N][N];

    inline void ck_min( int &a, int b ) { if( a > b ) a = b; }
    inline void ck_max( int &a, int b ) { if( a < b ) a = b; }

    inline bool check( int x, int y, int val )
    {
        int res = INF;
        for( int i = 0; i <= 100; i ++ )
            for( int j = 0; j <= 100; j ++ )
                if( f[i][j] >= 0 ) ck_min( res, i*x + j*y + f[i][j] );

    //  printf( "x:%d, y:%d, res:%d\n", x, y, res );
        return res == val;
    }

    int main()
    {
        memset( f, -1, sizeof( f ) );

        scanf( "%d%d", &a, &b );
        for( int i = 1; i <= a; i ++ )
            for( int j = 1; j <= b; j ++ )
                scanf( "%d", &d[i][j] );

        s = 201, t = 202; 
        // s --> 1 --> 2 --> ... --> 100
        // t <-- 101 <-- 102 <-- ... <-- 200

        for( int i = 0; i <= 100; i ++ )
            for( int j = 0; j <= 100; j ++ )
            {
                int tmp = -INF;
                for( int _a = 1; _a <= a; _a ++ )
                    for( int _b = 1; _b <= b; _b ++ )
                        ck_max( tmp, d[_a][_b] - i*_a - j*_b ); 
                f[i][j] = tmp; 
                if( f[i][j] < 0 ) break;

                sum ++;
    //          printf( "i:%d, j:%d, f:%d\n", i, j, f[i][j] );
            }

        for( int i = 1; i <= a; i ++ )
            for( int j = 1; j <= b; j ++ )  
                if( !check( i, j, d[i][j] ) ) {
                    printf( "Impossible\n" ); return 0;
                } 

        printf( "Possible\n" );

        printf( "%d %d\n", 202, sum+200 );
        for( int i = 1; i < 100; i ++ )
            printf( "%d %d X\n%d %d Y\n", i, i+1, i+101, i+100 );

        printf( "%d %d X\n%d %d Y\n", s, 1, 101, t );
        for( int i = 0; i <= 100; i ++ )
            for( int j = 0; j <= 100; j ++ )
                if( f[i][j] >= 0 )  printf( "%d %d %d\n", !i ? s : i, !j ? t : j+100, f[i][j] );

        printf( "%d %d\n", s, t );

        return 0;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章