算法競賽入門經典(第2版)—第十一章(圖論)

零碎知識點

題目

12219 - Common Subexpression Elimination

題目鏈接:UVA12219 公共表達式消除
思路:

代碼:

#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;

const int mx = 60000;
int T, rnd, cnt;
char expr[mx * 5], *p;
int done[mx];
struct Node//子樹的結構體
{
	string s;//存子樹字母
	int left, right;
	bool operator < (const Node&b)const//由於下面要用到map::count函數,所以必須要重載小於號
	{
		if (s != b.s)return s < b.s;
		if (left != b.left)return left < b.left;//哈希相同則比較出現的順序
		return right < b.right;
	}
}node[mx];
map <Node, int>dict;//記錄子樹的編號

//爲所有的子樹編號
int solve()
{
	int id = cnt++;//從0開始編號,將子樹映射爲編號
	//初始化一個子樹
	Node&u = node[id];
	u.left = u.right = -1;
	u.s = "";

	while (isalpha(*p))//獲取子樹的根節點的字符串
	{
		u.s.push_back(*p);//將該子樹的字母放入s
		p++;//向後掃描,遇到括號停止
	}
	if (*p == '(')//(L,R),遞歸處理左右子樹
	{
		p++;//先跳過'('
		u.left = solve(), p++;//返回左子樹編號,並跳過','
		u.right = solve(),p++;//返回右子樹編號,並跳過')'
	}
	if (dict.count(u))
	{
		cnt--;//子樹出現過,個數減少1
		return dict[u];//返回這顆子樹的編號
	}
	return dict[u] = id;//如果這棵樹是首次出現,給它編號
}
void print(int v)
{
	if(done[v] == rnd) printf("%d", v + 1);//已經輸出過了,輸出序號即可
	else
	{
		done[v] = rnd;//不需要對done數組初始化,只需要用這一輪特有的rnd標記即可
		printf("%s", node[v].s.c_str());//輸出樹根的字母
		if (node[v].left != -1)//含有左右子樹
		{
			putchar('(');
			print(node[v].left);//遞歸輸出左右子樹
			putchar(',');
			print(node[v].right);
			putchar(')');
		}
	}
}

int main()
{
	//freopen("test.txt", "r", stdin);
	scanf("%d", &T);
	for (rnd = 1; rnd <= T;rnd++)
	{
		dict.clear();
		cnt = 0;
		scanf("%s", expr);
		p = expr;//用指針p掃描expr
		print(solve());
		putchar(10);//打印換行符
	}
	return 0;
}
1662 - Brackets Removal

題目鏈接:1662 - Brackets Removal
參考博文:Brackets Removal UVA - 1662

1395 - Slim Span

題目鏈接:1395 - Slim Span
題目大意:給出一個n結點圖,求最大邊減最小邊儘量小的生成樹。
思路:我使用了二分+kruskal算法。先二分遍歷最大邊減最小邊的值,然後求滿足該條件下是否存在生成樹,如果存在可以減小該值,如果不存在則增加該值。

代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

struct Node
{
    int a, b, w;
    Node(int a=-1, int b=-1, int w=-1):a(a), b(b), w(w){}
    bool operator < (Node &A) const
    {
        if(w==A.w)
            return a<A.a;
        else
            return w<A.w;
    }
};
Node E[10000];
vector<int> v;
int father[105], Rank[105];
int n, m;

//並查集操作
void Init()
{
    for(int i=0; i<105; i++)
    {
        father[i] = i;
        Rank[i] = 1;
    }
}
int findRoot(int x)
{
    int r = x;
    while(r!=father[r]) r = father[r];
    int j = x, i;
    while(j!=father[j])
    {
        i = father[j];
        father[j] = r;
        j = i;
    }
    return r;
}
void join(int x, int y)
{
    int fx = findRoot(x), fy = findRoot(y);
    if(fx!=fy)
    {
        if(Rank[x]>Rank[y]) father[fy] = fx;
        else
        {
            father[fx] = fy;
            if(Rank[x]==Rank[y]) Rank[fy]++;
        }
    }
}
bool same(int x, int y)
{
    return findRoot(x)==findRoot(y);
}

//判斷在最大值減最小值不超過mid的情況下,是否存在生成樹(kruskal算法)
bool solve(int mid)
{
    for(int i=0; i<=m-(n-1); i++)//i表示起始的邊
    {
        Init();
        v.clear();
        for(int j=i; j<m; j++)//遍歷
        {
            if(E[j].w-E[i].w>mid) break;//超過條件,退出
            if(!same(E[j].a, E[j].b))
            {
                join(E[j].a, E[j].b);
                v.push_back(E[j].w);
            }
        }
        if(v.size()==n-1) return 1;//存在生成樹
    }
    return 0;//不存在生成樹
}
int main()
{
    while(cin >> n >> m && (n+m))
    {
        for(int i=0; i<m; i++)
            cin >> E[i].a >> E[i].b >> E[i].w;
        sort(E, E+m);
        //二分枚舉
        int l = 0, r = E[m-1].w-E[0].w+1, mid;
        for(int i=0; i<100; i++)
        {
            mid = (l+r)/2;
            if(solve(mid)) r = mid;//滿足條件,則減小mid
            else           l = mid;
        }

        if(r!=E[m-1].w-E[0].w+1)
            printf("%d\n", r);
        else
            printf("-1\n");
    }
    return 0;
}
1151 - Buy or Build

題目鏈接:1151 - Buy or Build

  • 題目大意:給定n個點,你的任務是讓它們都連通。你可以新建一些邊,費用等於兩點距離的平方(當然越小越好),另外還有幾種“套餐”,可以購買,你購買的話,那麼有些邊就可以連接起來,每個“套餐”,也是要花費的,讓你求出最少花費。
  • 思路:先在不加套餐的情況下存儲MST所有的邊,然後枚舉套餐,將套餐內的點集合爲一個並查集,然後在原MST的邊中選邊彌補套餐的不足(將所有點連通起來)。

代碼:

#include <bits/stdc++.h>
using namespace std;
vector<int> pl[10];
int cost[10],x[1005],y[1005],pre[1005];
int medge[1005];
struct node
{
    int u,v,dis;
    bool operator < (const struct node a) const
    {
        return dis < a.dis;
    }
}edge[1005 * 1005];

int dist(int i,int j)
{
    return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
}
int findset(int x)
{
    if(x == pre[x]) return x;
    else return pre[x] = findset(pre[x]);
}
inline bool join(int x,int y)
{
    int fx,fy;
    fx = findset(x),fy = findset(y);
    if(fx != fy) {
        pre[fy] = fx;
        return true;
    }
    return false;
}
void init(int n)
{
    for(int i = 1; i <= n; ++i) {
            pre[i] = i;
    }
}
int main(void)
{
    int T,n,num,cnt,temp,edge_cnt,ans,anss,flag = 0;
    scanf("%d",&T);
    while(T--) {
        scanf("%d %d",&n,&num);
        //套餐
        for(int i = 0; i < num; ++i) {
            scanf("%d %d",&cnt,&cost[i]);
            pl[i].clear();
            while(cnt--) {
                scanf("%d",&temp);
                pl[i].push_back(temp);
            }
        }
        //座標
        for(int i = 1; i <= n; ++i) {
            scanf("%d %d",&x[i],&y[i]);
        }
        edge_cnt = 0;

        for(int i = 1; i <= n; ++i) {
            for(int j = i + 1; j <= n; ++j) {
                edge[edge_cnt].u = i;
                edge[edge_cnt].v = j;
                edge[edge_cnt].dis = dist(i,j);
                edge_cnt++;
            }
        }
        sort(edge,edge + edge_cnt);
        cnt = 0;
        ans = 0;
        init(n);
        //不加套餐的MST
        for(int i = 0; i < edge_cnt; ++i) {
            if(join(edge[i].u,edge[i].v)) {
                medge[cnt] = i;
                ans += edge[i].dis;
                cnt++;
            }
            if(cnt == n - 1) break;
        }
        //枚舉套餐
        for(int i = 0;i < (1 << num); ++i) {
            init(n);
            anss = 0,cnt = 0;
            for(int j = 0; j < num; ++j) {
                if(i & (1 << j)) {//如果使用該套餐
                    temp = pl[j][0];
                    anss += cost[j];
                    //將套餐內的點集合爲一個並查集
                    for(int k = 1; k < pl[j].size(); k++) {
                        if(join(pl[j][k],temp)) cnt++;
                    }
                }
            }
            //在原始的MST邊中取出一些邊來彌補選擇套餐後不連通的點
            for(int j = 0; j <= n - 1; ++j) {
                if(join(edge[medge[j]].u,edge[medge[j]].v)) {
                    anss += edge[medge[j]].dis;
                    cnt++;
                }
                if(cnt == n - 1) break;
            }
            ans = min(ans,anss);
        }
        if(flag) {
            printf("\n");
        }
        flag = 1;
        printf("%d\n",ans);
    }
    return 0;
}
247 - Calling Circles

題目鏈接:247 - Calling Circles

  • 題目大意:輸出所有電話圈(電話圈:要求兩個人直接或間接互相接通)。
  • 思路:使用floyd判斷通路。先使用鄰接矩陣保存邊,然後使用floyd求出每兩個點之間是否有通路。當且僅當兩個點之間互相可達,才表示二者在一個圈內。

代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <set>
using namespace std;

const int INF = 1<<29;
int m, n;
int flag[30];
string A, B;
int G[30][30];
map<int, string> M;
map<string, int> ID;
set<string> Set;
int d[30][30];

void Init()
{
    M.clear();
    ID.clear();
    Set.clear();
    memset(G, 0, sizeof(G));
}
//將字符串轉換爲數字
int setID(string a)
{
    if(ID.count(a)) return ID[a];
    int t = Set.size();
    ID[a] = t;
    M[t] = a;
    Set.insert(a);
    return ID[a];
}
void floyd()
{
    for(int k=0; k<m; k++)
    {
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<m; j++)
            {
                G[i][j] = G[i][j] || (G[i][k]&&G[k][j]);//維護更新通路矩陣
            }
        }
    }
}
int main()
{
    int kase = 1;
    while(cin >> m >> n && (m+n))
    {
        Init();
        for(int i=0; i<n; i++)
        {
            cin >> A >> B;
            int a = setID(A), b = setID(B);
            G[a][b] = 1;//a可以到達b
        }
        floyd();
        if(kase>1) cout << endl;
        cout << "Calling circles for data set " << kase++ << ":" << endl;
        //按格式輸出
        memset(flag, 0, sizeof(flag));
        for(int i=0; i<m; i++)
        {
            if(flag[i]) continue;
            cout << M[i];
            flag[i] = 1;
            for(int j=0; j<m; j++)
            {
                if(i==j) continue;
                if(flag[j]) continue;
                if(G[i][j]==1 && G[j][i]==1)
                {
                    flag[j] = 1;
                    cout << ", " << M[j];
                }
            }
            cout << endl;
        }
    }
    return 0;
}
10048 - Audiophobia

題目鏈接:10048 - Audiophobia

  • 題目大意:給出一個c個點,s條邊組成的無向圖,求一點到另一點的路徑上最大權值最小的路徑,輸出這個值。
  • 思路:二分法+bfs。先將所有邊存儲排序,然後二分枚舉邊,使用bfs判斷是否存儲每一邊均不大於該值的情況下是否存在一條路徑,如果存在則將該值變小,否則將該值變大。

代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;

const int INF = 1<<29;
int C, S, Q;
int a, b, w, c1, c2;
vector<int> v;//存儲所有邊的權值
int G[105][105];
int vis[105];

void Init()
{
    v.clear();
}
//使用bfs來判斷是否存在一條路徑,路徑上的各個邊的權值均不大於v[mid]
bool solve(int mid)
{
    memset(vis, 0, sizeof(vis));
    queue<int> q;
    q.push(c1);
    vis[c1] = 1;
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        if(u==c2) return 1;
        for(int i=1; i<=C; i++)
        {
            if(!vis[i] && G[u][i]<=v[mid])
            {
                vis[i] = 1;
                q.push(i);
            }
        }
    }
    return 0;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
#endif
    int kase = 1;
    while(scanf("%d%d%d", &C, &S, &Q)!=EOF && (C+S+Q))
    {
        //初始化
        Init();
        for(int i=0; i<105; i++)
        {
            for(int j=0; j<105; j++)
                G[i][j] = INF;
        }
        for(int i=0; i<S; i++)
        {
            scanf("%d%d%d", &a, &b, &w);
            G[a][b] = w, G[b][a] = w;
            v.push_back(w);
        }
        sort(v.begin(), v.end());
        if(kase>1) printf("\n");
        printf("Case #%d\n", kase++);
        for(int i=1; i<=Q; i++)
        {
            scanf("%d%d", &c1, &c2);
            //二分法求值
            int l = 0, r = v.size();
            int cnt = (l+r)/2, mid = (l+r)/2;
            for(int i=0; i<100; i++)
            {
                if(solve(mid)) r = mid;
                else           l = mid;
                mid = (l+r)/2;
                if(mid==cnt) break;
                cnt = mid;
            }
            if(r==v.size())//不存在路徑
                printf("no path\n");
            else
                printf("%d\n", v[r]);
        }
    }
    return 0;
}
658 - It’s not a Bug, it’s a Feature!

題目鏈接:658 - It’s not a Bug, it’s a Feature!
參考博文:洛谷 題解 UVA658 【這不是bug,而是特性 It’s not a Bug, it’s a Feature!】

  • 題目大意:補丁在修正BUG時,有時也會引入新的BUG,假定有n(n<=20)個潛在BUG,和m(m<=100)個補丁,每個補丁用兩個長度爲n的字符串表示,其中字符串的每個位置表示一個BUG,第一個串表示打補丁之前的狀態 (“-”表示該BUG必須不存在,“+”表示該補丁必須存在,0表示無所謂),第二串表示打補丁之後的狀態 ("-“表示不存在,”+"表示存在,"0"表示不變)。每個補丁有一定的執行時間,你的任務是用最小的時間把所有BUG都存在的軟件變得沒有BUG。
    代碼:
#include<bits/stdc++.h>
using namespace std;

const int MAXN=20+10,MAXM=100+10;
int n,m;

struct Node
{
    int t;
    int a[MAXN];//狀態由a轉換爲b
    int b[MAXN];
}patch[MAXM];
int d[2000000];//保存路徑長度
int T;

void init(int k)
{
    cin>>patch[k].t;//該補丁的花費
    string s;
    cin>>s;//打補丁之前的狀態
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='-')patch[k].a[i+1]=-1;
        else if(s[i]=='0')patch[k].a[i+1]=0;
        else patch[k].a[i+1]=1;
    }
    cin>>s;//打補丁之後的狀態
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='-')patch[k].b[i+1]=-1;
        else if(s[i]=='0')patch[k].b[i+1]=0;
        else patch[k].b[i+1]=1;
    }
}
//查看該當前狀態是否可以使用第k個補丁
bool check(int sum,int k)//sum表示當前狀態,k表示第k個補丁
{
    for(int i=1;i<=n;i++)//比對當前狀態是否與補丁的應用狀態相同
    {
        if(patch[k].a[i]==0)continue;
        if(patch[k].a[i]==-1 && (sum>>(n-i)&1)==0)continue;
        if(patch[k].a[i]==1 && (sum>>(n-i)&1)==1)continue;
        return 0;
    }
    return 1;
}
//獲取使用第k個補丁轉化後的狀態
int get(int sum,int k)//sum表示當前狀態,k表示第k個補丁
{
    for(int i=1;i<=n;i++)//使用補丁轉化當前狀態sum
    {
        if(patch[k].b[i]==0)continue;//該位不需要轉化
        if(patch[k].b[i]==-1)//將對應位變成0
        {
            int t = (1<<n)-1-(1<<(n-i));
            sum = sum&t;
        }
        else//將對應位變成1
        {
            int t = 1<<(n-i);
            sum = sum|t;
        }
    }
    return sum;
}
void SPFA()
{
    memset(d,0x3f,sizeof(d));
    queue<int>q;
    q.push((1<<n)-1);//初始全部均爲bug,每一位均爲1
    d[(1<<n)-1]=0;
    while(q.size())
    {
        int now=q.front();
        q.pop();
        //枚舉m個補丁
        for(int i=1;i<=m;i++)
        {
            if(!check(now,i))continue;
            int x=get(now,i);//獲取使用第i個補丁轉化後的狀態
            if(d[now]+patch[i].t<d[x])
            {
                d[x]=d[now]+patch[i].t;
                q.push(x);
            }
        }
    }
}
int main()
{
    while(cin>>n>>m)
    {
        if(n==0&&m==0)break;
        T++;
        for(int i=1;i<=m;i++)
            init(i);
        SPFA();
        printf("Product %d\n",T);
        if(d[0]==0x3f3f3f3f)
            printf("Bugs cannot be fixed.\n");
        else
            printf("Fastest sequence takes %d seconds.\n",d[0]);
        cout<<endl;
    }
    return 0;
}
12661 - Funny Car Racing

題目鏈接:12661 - Funny Car Racing

  • 題目大意:給出一個有向圖,每條邊都有三個值,打開時間間隔,關閉時間間隔,通過它需要多少時間,路的開關是循環往復的。給你起點和終點,問你最少需要多少時間纔可以從起點到達終點(保證一定存在這種路)。
  • 思路:dijstra的變體。由於路有開關,所以需要在計算從一個點到達另一個點的時間,主要是更新距離d時,需要分條件判斷(是否能夠直接通過或者等待)。

代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXM = 50001;
const int MAXN = 500;
const int INF = 1<<29;
int d[MAXN], vis[MAXN];
int n, m, s, t;
int u, v, a, b, t1;
struct Node
{
    int v, a, b, t;
    Node(int v=-1, int a=-1, int b=-1, int t=-1):v(v), a(a), b(b), t(t){}
};
vector<Node> G[MAXM];

void dijstra(int s)
{
    memset(vis, 0, sizeof(vis));
    fill(d, d+MAXN, INF);
    d[s] = 0;
    while(1)
    {
        int minv = INF, u = 0;
        for(int i=1; i<=n; i++)
        {
            if(!vis[i] && minv>d[i])
            {
                minv = d[i];
                u = i;
            }
        }
        if(minv==INF)
        {
            cout << d[t] << endl;
            return;
        }
        vis[u] = 1;
        for(int i=0; i<G[u].size(); i++)
        {
            Node v = G[u][i];
            if(vis[v.v]) continue;
            int r = d[u]%(v.a+v.b);
            if(r+v.t<=v.a)//可以在關閉前通過
            {
                if(d[v.v]>d[u]+v.t)
                    d[v.v] = d[u]+v.t;
            }
            else if(v.t<=v.a)//在關閉後重新打開時通過
            {
                if(d[v.v]>d[u]+v.t+v.a+v.b-r)
                    d[v.v] = d[u]+v.t+v.a+v.b-r;
            }
        }
    }
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
#endif
    int kase = 1;
    while(cin >> n >> m >> s >> t)
    {
        for(int i=0; i<m; i++)
        {
            cin >> u >> v >> a >> b >> t1;
            G[u].push_back(Node(v, a, b, t1));
        }
        cout << "Case " << kase++ << ": ";
        dijstra(s);
        for(int i=1; i<=n; i++) G[i].clear();
    }
    return 0;
}
821 - Page Hopping

題目鏈接:821 - Page Hopping

  • 題目大意:給出有向圖,給定的節點之間長度爲1,求出平均長度,既所有道路長度和/道路數量。
  • 思路:簡單floyd題目。直接使用floyd統計任意兩個點之間的距離,然後求其平均即可。

代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;

const int MAX = 105;
const int INF = 1<<29;
int G[MAX][MAX], N;

void Init()
{
    for(int i=0; i<MAX; i++)
    {
        for(int j=0; j<MAX; j++)
        {
            G[i][j] = INF;
        }
    }
}
void floyd()
{
    for(int k=1; k<=N; k++)
    {
        for(int i=1; i<=N; i++)
        {
            if(G[i][k]==INF) continue;
            for(int j=1; j<=N; j++)
            {
                if(G[k][j]==INF) continue;
                G[i][j] = min(G[i][j], G[i][k]+G[k][j]);
            }
        }
    }
}
int main()
{
    int a, b, kase = 1;
    while(cin >> a >> b && (a+b))
    {
        Init();
        N = 0;
        G[a][b] = 1;
        N = max(a, b);
        while(cin >> a >> b && (a+b))
        {
            G[a][b] = 1;
            N = max(N, a);
            N = max(N, b);
        }
        floyd();
        int sum = 0, cnt = 0;
        for(int i=1; i<=N; i++)
        {
            for(int j=1; j<=N; j++)
            {
                if(i==j) continue;
                if(G[i][j]!=INF)
                {
                    sum += G[i][j];
                    cnt++;
                }
            }
        }
        printf("Case %d: average length between pages = %.3f clicks\n", kase++, sum/(cnt*1.0));
    }
    return 0;
}
10801 - Lift Hopping

題目鏈接:10801 - Lift Hopping

  • 題目大意:有一棟100層的大樓(標號爲0~99),裏面有n個電梯(不超過5個),以及要到達的層數(aid),然後是每個電梯走一層所需的時間,再n行就是對應每個電梯可以到達的層數,數量不定。然後每裝換一次電梯需要等待60秒,問,最快能多快到達目標層數。
  • 思路:最短路問題。這道題的難點在於將問題轉換爲最短路問題,並且需要自己建圖。通過將一個電梯可以到達的樓層看做點,通過電梯在兩個可以停靠的點之間的用時看做邊的權值(取權值最小即可)。而在換電梯時需要考慮將換電梯的時間,這個在求最短路的過程中可以考慮。以下是我使用floyd算法的解法。

代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <cmath>
#include <set>
using namespace std;

const int INF = 1<<29;
int T[10], n, k, m;
int f[10][101], G[101][101];
string s;
set<int> S;//儲存所有點

void Init()
{
    S.clear();
    for(int i=0; i<101; i++)
    {
        for(int j=0; j<101; j++)
        {
            G[i][j] = INF;
        }
    }
}
void floyd()
{
    set<int>::iterator k, i, j;
    for(k=S.begin(); k!=S.end(); k++)
    {
        for(i=S.begin(); i!=S.end(); i++)
        {
            if(G[*i][*k]==INF || *i==*k) continue;
            for(j=S.begin(); j!=S.end(); j++)
            {
                if(G[*k][*j]==INF || *k==*j) continue;
                G[*i][*j] = min(G[*i][*j], G[*i][*k]+G[*k][*j]+60);//通過k來換電梯
            }
        }
    }
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
#endif
    int x;
    while(cin >> n >> m)
    {
        Init();
        for(int i=0; i<n; i++)
            cin >> T[i];
        getchar();
        for(int i=0; i<n; i++)
        {
            getline(cin, s);
            stringstream ss(s);
            int t = 0;
            while(ss >> x)
            {
                f[i][t++] = x;
                S.insert(x);
            }
            //建立圖
            for(int j=0; j<t; j++)
            {
                int a = f[i][j];
                for(int k=0; k<t; k++)
                {
                    int b = f[i][k];
                    G[a][b] = min(G[a][b], T[i]*abs(a-b));//注意使用min
                    G[b][a] = G[a][b];
                }
            }
        }
        floyd();
        if(G[0][m]==INF) printf("IMPOSSIBLE\n");
        else             printf("%d\n", G[0][m]);
    }
    return 0;
}
11671 - Sign of Matrix

題目鏈接:11671 - Sign of Matrix
參考博文:Uva11671_Sign of Matrix——差分約束

表達式總結

參考博文:表達式總結

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