usaco training 4.1.3 fence6 题解

Fence Loops题解

The fences that surround Farmer Brown's collection of pastures have gotten out of control. They are made up of straight segments from 1 through 200 feet long that join together only at their endpoints though sometimes more than two fences join together at a given endpoint. The result is a web of fences enclosing his pastures. Farmer Brown wants to start to straighten things out. In particular, he wants to know which of the pastures has the smallest perimeter.

Farmer Brown has numbered his fence segments from 1 to N (N = the total number of segments). He knows the following about each fence segment:

  • the length of the segment
  • the segments which connect to it at one end
  • the segments which connect to it at the other end.
Happily, no fence connects to itself.

Given a list of fence segments that represents a set of surrounded pastures, write a program to compute the smallest perimeter of any pasture. As an example, consider a pasture arrangement, with fences numbered 1 to 10 that looks like this one (the numbers are fence ID numbers):

           1
   +---------------+
   |\             /|
  2| \7          / |
   |  \         /  |
   +---+       /   |6
   | 8  \     /10  |
  3|     \9  /     |
   |      \ /      |
   +-------+-------+
       4       5

The pasture with the smallest perimeter is the one that is enclosed by fence segments 2, 7, and 8.

PROGRAM NAME: fence6

INPUT FORMAT

Line 1:N (1 <= N <= 100)
Line 2..3*N+1:

N sets of three line records:

  • The first line of each record contains four integers: s, the segment number (1 <= s <= N); Ls, the length of the segment (1 <= Ls <= 255); N1s (1 <= N1s <= 8) the number of items on the subsequent line; and N2sthe number of items on the line after that (1 <= N2s <= 8).
  • The second line of the record contains N1 integers, each representing a connected line segment on one end of the fence.
  • The third line of the record contains N2 integers, each representing a connected line segment on the other end of the fence.

OUTPUT FORMAT

The output file should contain a single line with a single integer that represents the shortest surrounded perimeter.


描述

农夫布朗的牧场上的篱笆已经失去控制了。它们分成了1~200英尺长的线段。只有在线段的端点处才能连接两个线段,有时给定的一个端点上会有两个以上的篱笆。结果篱笆形成了一张网分割了布朗的牧场。布朗想将牧场恢复原样,出于这个考虑,他首先得知道牧场上哪一块区域的周长最小。 布朗将他的每段篱笆从1到N进行了标号(N=线段的总数)。他知道每段篱笆有如下属性:

  • 该段篱笆的长度
  • 该段篱笆的一端所连接的另一段篱笆的标号
  • 该段篱笆的另一端所连接的另一段篱笆的标号

幸运的是,没有篱笆连接它自身。对于一组有关篱笆如何分割牧场的数据,写一个程序来计算出所有分割出的区域中最小的周长。

例如,标号1~10的篱笆由下图的形式组成(下面的数字是篱笆的标号):

         1
 +---------------+
 |\             /|
2| \7          / |
 |  \         /  |
 +---+       /   |6
 | 8  \     /10  |
3|     \9  /     |
 |      \ /      |
 +-------+-------+
     4       5

上图中周长最小的区域是由2,7,8号篱笆形成的。

[编辑]格式

PROGRAM NAME: fence6

INPUT FORMAT:

(file fence6.in)

第1行: N (1 <= N <= 100)

第2行到第3*N+1行: 每三行为一组,共N组信息:

每组信息的第1行有4个整数: s, 这段篱笆的标号(1 <= s <= N); Ls, 这段篱笆的长度 (1 <= Ls <= 255); N1s (1 <= N1s <= 8) 与本段篱笆的一端 所相邻的篱笆的数量; N2s与本段篱笆的另一端所相邻的篱笆的数量。 (1 <= N2s <= 8).

每组信息的的第2行有 N1s个整数, 分别描述与本段篱笆的一端所相邻的篱笆的标号。

每组信息的的第3行有N2s个整数, 分别描述与本段篱笆的另一端所相邻的篱笆的标号。

OUTPUT FORMAT:

(file fence6.out)

输出的内容为单独的一行,用一个整数来表示最小的周长。

[编辑]SAMPLE INPUT

10
1 16 2 2
2 7
10 6
2 3 2 2
1 7
8 3
3 3 2 1
8 2
4
4 8 1 3
3
9 10 5
5 8 3 1
9 10 4
6
6 6 1 2 
5 
1 10
7 5 2 2 
1 2
8 9
8 4 2 2
2 3
7 9
9 5 2 3
7 8
4 5 10
10 10 2 3
1 6
4 9 5

[编辑]SAMPLE OUTPUT

12

-------------------------------------------------分割线-----------------------------------------------------------

这道题可以看出是求最小环。因为n的范围很小,可以采用如下方法:

①floyd求最小环(更推荐这个,因为代码简洁)

②用最短路的dijskra算法或是SPFA算法,每次删掉一条边求最短路,如果从左侧顶点到右侧定点仍存在最短路,那么加上这条边后,就是一个最小环了。同时更新答案。

但是我想说,这两种方法都不好O(∩_∩)O~~

因为读入的是边集而不是我们日常做的点集,所以在转化的过程中会比较麻烦。推荐用DFS直接0ms秒过。


代码:

/*
ID:juan1973
LANG:C++
PROG:fence6
*/
 
#include<stdio.h>
#include<cstring>
using namespace std;
const int maxn=101;
int num[maxn][2],map[maxn][2][10],f[maxn],n,i,ans,start,c,j;
bool flag[maxn];
int find(int a,int b)
{
  for (int i=1;i<=num[b][0];i++)
    if (map[b][0][i]==a) return 0;
  return 1;
}
void dfs(int k,int d,int s)
{
  if (s>ans) return;
  if (k==start&&s>0) {ans=s;return;}
  flag[k]=true;
  for (int i=1;i<=num[k][d];i++)
  {
    int go=map[k][d][i];
    if (!flag[go]||go==start) dfs(go,1-find(k,go),s+f[k]);
  }
  flag[k]=false;
}
int main()
{
  freopen("fence6.in","r",stdin);
  freopen("fence6.out","w",stdout);
  scanf("%ld",&n);
  for (i=1;i<=n;i++)
  {
    scanf("%ld",&c);
    scanf("%ld%ld%ld",&f[c],&num[c][0],&num[c][1]);
    for (j=1;j<=num[c][0];j++) scanf("%ld",&map[c][0][j]);
    for (j=1;j<=num[c][1];j++) scanf("%ld",&map[c][1][j]);
  }
  ans=9999999;
  for (start=1;start<=n;start++)
    {
      memset(flag,0,sizeof(flag));
      dfs(start,0,0);
    }
  printf("%ld\n",ans);
  return 0;
}
//果断放弃一下转化代码。  
/*for (i=1;i<=n;i++)
  
    scanf("%ld%ld%ld%ld",&p[i],&map_e[i],&map[0][p[i]][0],map[1][p[i]][0]);
    for (j=1;j<=map[0][p[i]][0];j++) scanf("%ld",&map[0][p[i]][j]);
    for (j=1;j<=map[1][p[i]][0];j++) scanf("%ld",&map[1][p[i]][j]);
  }
  flag[0][1]=true;now_e=1;now_v;cnt=1;
  while (true)
  {
    for (i=1;i<=n;i++) 
      {
        find=false;
        for (j=0;j<=1;j++)
          for (k=1;k<=map[j][i][0];k++)
            if (map[j][i][k]==now_e)*/                   

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
USACO2022金组是国际在线判题系统USACO的最高级别,题目难度较高,在该比赛中取得好成绩是一项巨大的成就。以下是对该比赛的一些题目解析。 第一题:“交通计划” 题目要求:给定一个n个节点的有向图,每条边有一个长度,希望添加最少的边使得所有节点连通,求最小生成树的权值和。 解析:该题可以使用Kruskal算法求解,将每条边按权值从小到大排序,再依次加入,判断加入的边是否会形成环,若形成则不加入,直到所有节点连通为止。此时Kruskal算法得到的最小生成树的权值和即为所求。 第二题:“点火计划” 题目要求:给定一个n个节点的有向图,每条边有一个权值和一个点火时长,每个节点有一个点火启动时刻和时刻结束时刻,希望从其中选出一些边点火,使得所有节点都可从点火的边出发到达,且所选点火边的总点火时长最小。 解析:该题可以使用最小费用最大流算法求解。将每条边看做一个容量为1,费用为点火时长的边,源点向节点的点火边容量为1,费用为0的边,节点的点火边向汇点的容量为1,费用为0的边,对这个网络进行最小费用最大流即可得到所选边的总点火时长最小。 第三题:“美味佳肴” 题目要求:给定n个菜品,每个菜品有它的权值和两个类别,希望选出k个菜品,使得选出的菜品数量在每个类别中都不超过$\frac{k}{3}$个,且所选菜品的权值和最大。 解析:该题可以使用动态规划求解。设$f[i][j][k]$表示前i个菜品中,选择j个一类菜品,选择k个二类菜品的最大权值和,状态转移方程为$f[i][j][k]=max(f[i-1][j][k],f[i-1][j-1][k]+a[i],f[i-1][j][k-1]+b[i])$,其中a[i]为i号菜品的权值,若为一类则为该权值,否则为0,b[i]为i号菜品的权值,若为二类则为该权值,否则为0。最终答案为$f[n][$k/3$][$k/3$]。 以上是对USACO2022金组的部分题目的解析,USACO比赛是全球范围内的计算机竞赛,竞争非常激烈,能够在该比赛中脱颖而出是一项非常棒的成就。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值