USACO 4.1 Fence loop

4 篇文章 0 订阅

题目大意是找出图中权值和最小的一个环,DFS加剪枝就行了,唯一有点恶心的是题目的输入给的是每条边的信息,不太好转化成图论中节点和边的集合,索性就不转化成图的常用表示形式了,这样倒是更方便一点。

这道题的主要思路就是暴力搜索,用变量min来记录最小环的周长,min初始化为图中所有边长的和,枚举以每一条边为起点沿着某一固定方向走,如果找到了一个比min 还小的环,则更新,如果在搜索过程中发现路径的长度超过了min,则果断掐掉,道理很简单,这条路径不可能找到比min还小的环了。

由于最近情绪不佳,大脑基本是一团乱,所以代码和题解都是在迷迷糊糊的状态下写的,如有写得不当的地方,敬请指正。 

代码如下:

#include<cstdio>
#include<cstdlib>

typedef struct
{
    int name,len;//name:边的编号(其实这个可以不要的);len:边的长度
    int l,r;//l:与这条边左端相连的边的条数;r....;(左和右是为了方便标识定义的)
    int larr[10],rarr[10];//larr:与这条边左端相连的边的编号;
}edge;

FILE *in,*out;
edge fence[105];
bool table[105];
int n,min;

void DFSfrom(int k);
void DFS(int *path,int index,int pid,int s);

int main()
{
    in=fopen("fence6.in","r");
    out=fopen("fence6.out","w");
    
    for(int i=0;i<105;i++) table[i]=false;
    fscanf(in,"%d",&n);
    for(int i=0;i<n;i++)
    {
        int id,len,l,r;
        fscanf(in,"%d%d%d%d",&id,&len,&l,&r);
        table[id]=true;
        fence[id].name=id;
        fence[id].len=len;
        min+=len;//min初始化为所有边长之和
        fence[id].l=l;
        fence[id].r=r;
        for(int j=0;j<l;j++) fscanf(in,"%d",&(fence[id].larr[j]));
        for(int j=0;j<r;j++) fscanf(in,"%d",&(fence[id].rarr[j]));
    }
    for(int i=0;i<105;i++)
    {
        if(table[i]) DFSfrom(i);
    }
    fprintf(out,"%d\n",min);
    fclose(in);
    fclose(out);
    return 0;
}

void DFSfrom(int k)
{
    int path[105];
    path[0]=k;
    DFS(path,0,k,0);
}

void DFS(int *path,int index,int pid,int s)//path用来记录搜索的路径;index主要记录path元素的个数(边的条数);pid:边的编号;s:路径的总长度
{
    s+=fence[pid].len;
    if(s>min) return ;//如果s>min说明这条路径不可能是最短的路径了,所以及时掐掉
    int oid=path[0];
    if(index>1)//根据题意一个区域至少要有三条边
    {
         for(int i=0;i<fence[oid].l;i++)
         {
               if(fence[oid].larr[i]==pid)//如果这条和路径中的第一条边是相连的则说明已形成环路,因为我假设搜索的方向是从第一条边的右端进行的,所以这里是fence[oid].larr[i]==pid;
               {
                     if(min>s) min=s;
                     return ;
               }
         }
    }
    //下面的操作是为了保证搜索朝固定方向进行
    bool flag=false;
    if(index>=1)
    {
         for(int i=0;i<fence[pid].r;i++)
         {
               if(path[index]==fence[pid].rarr[i])
               {
                     flag=true;
                     break;
               }
         }
    }
    path[++index]=pid;
    int *list,len;
    if(flag)
    {
         list=fence[pid].larr;
         len=fence[pid].l;
    }
    else
    {
         list=fence[pid].rarr;
         len=fence[pid].r;
    }
    for(int i=0;i<len;i++)
    {
         DFS(path,index,list[i],s);
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值