POJ3228 Gold Transportation 解题报告【贪心+并查集=Kruskal?】

Description
Recently, a number of gold mines have been discovered in Zorroming State. To protect this treasure, we must transport this gold to the storehouses as quickly as possible. Suppose that the Zorroming State consists of N towns and there are M bidirectional roads among these towns. The gold mines are only discovered in parts of the towns, while the storehouses are also owned by parts of the towns. The storage of the gold mine and storehouse for each town is finite. The truck drivers in the Zorroming State are famous for their bad temper that they would not like to drive all the time and they need a bar and an inn available in the trip for a good rest. Therefore, your task is to minimize the maximum adjacent distance among all the possible transport routes on the condition that all the gold is safely transported to the storehouses.

Input
The input contains several test cases. For each case, the first line is integer N(1<=N<=200). The second line is N integers associated with the storage of the gold mine in every towns .The third line is also N integers associated with the storage of the storehouses in every towns .Next is integer M(0<=M<=(n-1)*n/2).Then M lines follow. Each line is three integers x y and d(1<=x,y<=N,0 < d<=10000), means that there is a road between x and y for distance of d. N=0 means end of the input.
Output
For each case, output the minimum of the maximum adjacent distance on the condition that all the gold has been transported to the storehouses or “No Solution”.
Sample Input
4
3 2 0 0
0 0 3 3
6
1 2 4
1 3 10
1 4 12
2 3 6
2 4 8
3 4 5
0
Sample Output
6
解题报告
这道题的题意是有n个村落,m条道路,每个村落有一定的金矿存量和仓库容量,问把所有金矿全部装进仓库里所要经过的所有路线中边权最大值中最小的那个。
我们首先要想一想怎样的情况可以叫做“所有的金矿都可以装进仓库里”。那必然是讲,对于经过调配后的每一个村庄中的金矿存量都要小于其仓库容量。
我们借用kruskal中贪心的思想,但是需要把并查集开成带权并查集,在形似kruskal的贪心地排序+贪心地选边的过程中,合并一条边的两个端点时顺带把两个权值一起合并了,再加以判断就行了。
代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200,M=20000;
struct edge
{
    int u,v,w;
}ed[M+5];
int n,m;
int w[N+5],s[N+5],father[N+5];
int answ,anss,ans;
bool cmp(edge a,edge b){return a.w<b.w;}
int find(int a){return father[a]==a?a:father[a]=find(father[a]);}
bool check()
{
    for(int i=1;i<=n;i++)
    {
        int u=find(i);
        if(s[u]<w[u])return false;
    }
    return true;
}
void kruskal()
{
    for(int i=1;i<=m;i++)
    {
        int u=ed[i].u,v=ed[i].v;
        u=find(u),v=find(v);
        if(u==v)continue;
        father[u]=v;
        w[v]+=w[u],w[u]=0;
        s[v]+=s[u],s[u]=0;
        ans=ed[i].w;
        if(check())return ;
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        answ=0,anss=0;
        if(!n)break;
        for(int i=1;i<=n;i++)father[i]=i;
        for(int i=1;i<=n;i++)scanf("%d",&w[i]),answ+=w[i];
        for(int i=1;i<=n;i++)scanf("%d",&s[i]),anss+=s[i];
        if(answ>anss){printf("No Solution\n");continue;}
        scanf("%d",&m);
        for(int i=1;i<=m;i++)scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);
        if(check()){printf("0\n");continue;}
        sort(ed+1,ed+1+m,cmp);
        kruskal();
        if(check())printf("%d\n",ans);
        else printf("No Solution\n");
    }
    return 0;
}

ps:听说可以用二分+最大流做?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 给定一个 $N \times M$ 的矩阵,其中 "." 表示水洼,"W" 表示水。请计算有多少个水洼。 解题思路: 这是一道非常经典的搜索题目。我们可以使用 DFS 或 BFS 进行求解。 首先,我们需要遍历整个矩阵,当我们遇到一个 "." 时,我们就从该点开始向四周搜索,将所有相邻的 "." 变为 "W" ,并继续向下搜索。每次搜索完毕后,我们就可以找到一个完整的水洼,计数器加一。最后,当我们遍历完整个矩阵后,就可以得到所有的水洼数量。 代码实现: 使用 DFS 进行搜索: ```c++ #include <iostream> using namespace std; const int maxn = 110; char field[maxn][maxn]; bool vis[maxn][maxn]; int n, m; void dfs(int x, int y) { vis[x][y] = true; for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { int nx = x + dx, ny = y + dy; if (nx >= 0 && nx < n && ny >= 0 && ny < m && !vis[nx][ny] && field[nx][ny] == '.') { dfs(nx, ny); } } } } int main() { cin >> n >> m; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> field[i][j]; } } int res = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (!vis[i][j] && field[i][j] == '.') { dfs(i, j); res++; } } } cout << res << endl; return 0; } ``` 使用 BFS 进行搜索: ```c++ #include <iostream> #include <queue> using namespace std; const int maxn = 110; char field[maxn][maxn]; bool vis[maxn][maxn]; int n, m; void bfs(int x, int y) { queue<pair<int, int>> q; q.push(make_pair(x, y)); vis[x][y] = true; while (!q.empty()) { int cx = q.front().first, cy = q.front().second; q.pop(); for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { int nx = cx + dx, ny = cy + dy; if (nx >= 0 && nx < n && ny >= 0 && ny < m && !vis[nx][ny] && field[nx][ny] == '.') { q.push(make_pair(nx, ny)); vis[nx][ny] = true; } } } } } int main() { cin >> n >> m; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> field[i][j]; } } int res = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (!vis[i][j] && field[i][j] == '.') { bfs(i, j); res++; } } } cout << res << endl; return 0; } ``` 时间复杂度: 两种方法的时间复杂度均为 $O(NM)$,其中 N 和 M 分别为矩阵的行数和列数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值