zoukankan      html  css  js  c++  java
  • 【BZOJ】3397: [Usaco2009 Feb]Surround the Islands 环岛篱笆(tarjan)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3397

    显然先tarjan缩点,然后从枚举每一个scc,然后向其它岛屿连费用最小的边,然后算最小的即可

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << #x << " = " << x << endl
    #define printarr2(a, b, c) for1(i, 1, b) { for1(j, 1, c) cout << a[i][j]; cout << endl; }
    #define printarr1(a, b) for1(i, 1, b) cout << a[i]; cout << endl
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    
    const int N=505;
    int ihead[N], mn[N][N], cnt, FF[N], LL[N], vis[N], tot, q[N], top, p[N], scc, n;
    struct ED { int to, next; }e[N*N<<1];
    void add(int u, int v) { 
    	e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; 
    	e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u; 
    }
    void tarjan(int u) {
    	int v;
    	FF[u]=LL[u]=++tot; q[++top]=u; vis[u]=1;
    	for(int i=ihead[u]; i; i=e[i].next) {
    		v=e[i].to;
    		if(!FF[v]) tarjan(v), LL[u]=min(LL[u], LL[v]);
    		else if(vis[v]) LL[u]=min(LL[u], FF[v]);
    	}
    	if(FF[u]==LL[u]) {
    		++scc;
    		do {
    			v=q[top--];
    			p[v]=scc;
    			vis[v]=0;
    		} while(u!=v);
    	}
    }
    
    int main() {
    	read(n);
    	for1(i, 1, n) {
    		int u=getint(), v=getint();
    		add(u, v);
    	}
    	for1(i, 1, n) if(!FF[i]) tarjan(i);
    	CC(mn, 0x3f);
    	for1(i, 1, n) for1(j, 1, n) {
    		int t=getint(), u=p[i], v=p[j];
    		if(u!=v && mn[u][v]>t) mn[u][v]=t;
    	}
    	int ans=~0u>>1;
    	for1(i, 1, scc) {
    		int t=0;
    		for1(j, 1, scc) if(i!=j)
    			t+=mn[i][j];
    		ans=min(t, ans);
    	}
    	print(ans<<1);
    	return 0;
    }
    

    Description

        约 翰在加勒比海买下地产,准备在这里的若干个岛屿上养奶牛.所以,他要给所有岛屿围上篱笆.每个岛屿都是多边形.他沿着岛屿的一条边界朝一个方向走,有时候 坐船到另一个岛去.他可以从任意一个多边形顶点开始修篱笆的工作;在任意一个到达的顶点,他可以坐船去另一个岛屿的某个顶点,但修完那个岛的篱笆,他必须 马上原路返回这个出发的岛屿顶点.任意两个顶点间都有肮线,每条航线都需要一定的费用.请帮约翰计算最少的费用,让他修完所有篱笆.

    Input

        第1行输入N(3≤N≤500),表示所有岛屿多边形的个数.
        接下来N行每行输入两个整数V1和V2(1≤V1≤N;1≤V2≤N),表示一条构成岛屿的线段的两个端点.接下来输入N行N列的矩阵,表示两个顶点间航行所需费用.

    Output

     
        一个整数,最少费用.

    Sample Input

    12
    1 7
    7 3
    3 6
    6 10
    10 1
    2 12
    2 9
    8 9
    8 12
    11 5
    5 4
    11 4
    0 15 9 20 25 8 10 13 17 8 8 7
    15 0 12 12 10 10 8 15 15 8 8 9
    9 12 0 25 20 18 16 14 13 7 12 12
    20 12 25 0 8 13 14 15 15 10 10 10
    25 10 20 8 0 16 20 18 17 18 9 11
    8 10 18 13 16 0 10 9 11 10 8 12
    10 8 16 14 20 10 0 18 20 6 16 15
    13 15 14 15 18 9 18 0 5 12 12 13
    17 15 13 15 17 11 20 5 0 22 8 10
    8 8 7 10 18 10 6 12 22 0 11 12
    8 8 12 10 9 8 16 12 8 11 0 9
    7 9 12 10 11 12 15 13 10 12 9 0

    Sample Output

    30

    HINT

    Source

  • 相关阅读:
    利用 .NET Framework 命令行工具
    和AI机器人Alice的一段聊天记录
    WINDOWS自启动程序的10大隐身之所
    开放式开发/开源项目TimeDog[C#WindowsApp]
    Microsoft月度中文速递
    新安装的VS2003出现了一个问题不能新建项目!
    实例构造器和类型构造器的一些比较
    C++ 模板里面的typename
    vim 折叠的用法
    Redis3:持久化
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/3983169.html
Copyright © 2011-2022 走看看