2020.7.15 1 or 2 dfs

和以前写过的一道题很像,感谢当初自己还去回顾了一下,看到这个结构就能理解个大概,代码倒是不难理解,都没用草稿纸,脑子里就有结果,yes
再次默写,别的都对,但是
clear又忘了
if(e[p]==0) return dfs(x+1)忘记了return ,失之毫厘谬以千里也

为什么要v要从小的到大的排序,因为如果是满足条件的话,边多的点很可能无法使得e[p]=0,但是边少的点很可能几下就ep=0,接着就可以进入下一环节了

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=105;
/*点最多50,线最多100*/
int e[55],vis[maxn],id[55],n,m;
/*e代表每个点的度数,vis代表这条线有没有被连过,id表示x点的初始下标*/
vector<pair<int,int>>v[55];
int cmp(int x,int y)
{
    return v[x].size()<v[y].size();
}
/*比如输入5条线,2 5   2 4   2 3   3 4   1 3,
2提及次数3,3是3,4是2,5是1,1是2,id排序按照提及次数从小到大排序,为5 1 4 2 3

小于号改成大于号的话,提交代码通过率为0,为什么?
以下输入
5 5
1 1 2 1 1
1 5
3 5
2 4
2 1
3 1
从大到小排序,1 2 3 5 4,依次进行处理
先链接1 2,1满了2,满了,直接跳到排序第三个,就是3那边。3 2不能连接,那就连3 5,最后只剩下节点3的一度和节点4的一度,找不到满足条件的线,return 0
但是这个例子是有解的,连接1 3 3 5 2 4即可【这是我随手敲的一个例子,没想到居然成了】
所以先考虑被q次数少的节点是吗?但是为什么呢?
*/
int dfs(int x)
{
    int p=id[x];
    if(x>n)  return 1;
    if(e[p]==0)  return dfs(x+1);
      for(auto i:v[p])
      {
          int conn=i.first,xian=i.second;
          if(e[conn]==0||vis[xian]) continue;
          e[conn]--;vis[xian]=1;e[p]--;
          if(dfs(x))  return 1;
          /*这个结构我们曾经见过,没想到又见面了,
          比如连线有 1 2   1 5   2 4等等,第一次dfs先认为1 2连接,然后进入第一次dfs中的第一次dfs,如果1的最大度数是1,那么1节点已经完成使命,看是dfs(x+1),就是进入对2节点的dfs,一直下去,直到dfs(n)执行完毕【if(x>n)  return 1的意义,这并不表示程序结束,整个dfs最终输出1与否在这个for循环里面,上面两个return不起终止作用】
  还没完,后面又回归,表示1 2这条线我不连接了(下面三个和上面相反的式子),我继续对v[1]循环(for走下去),找到1 5这条线,我连接他们,再用这个连好的结果dfs,直到走到dfs(n)*/
          e[conn]++;vis[xian]=0;e[p]++;
      }
    return 0;
    /*代表连接中,无法满足某个的节点度数,比如线1 2 2 3,但是要求节点1有度数2,无法满足,就结束程序。取个极限,比如3节点度数为1,但是连线中根本没有连接节点3的线,这时开头三个岿然不动,for循环size为0,根本不进入,就return 0
    以下证明>=2时有个return 0就全局return 0
    还是上面这个3的例子,dfs(3)的计算是由if(e[p]==0)  return dfs(x+1);
    带出的(此时x=2),dfs3返回了0,下面的for都不进行,我们看看这个return是返回给谁的。因为能进入dfs3的情况当且仅当e[p]=0,又因为题目规定每个点的度数在1到2之间,所以在dfs的时候,比如他们连接了2 5线什么的,又或者还有一条2 4线,但是dfs3永远返回3,dfs3的返回值最终作用于这一条【 if(dfs(x))  return 1;】,于是fs2的每个for循环都无法return 这个1,所以for循环最终会自然结束而不是被return 1打断,至此dfs2返回0,dfs1以此类推*/

}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&e[i]);
            id[i]=i;
            v[i].clear();
            /*clear不加只能过5%案例,惨痛*/
        }
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            v[x].push_back(make_pair(y,i));
            v[y].push_back(make_pair(x,i));
            /*x连接y,这是第i条线,第二个push同理*/

        }
          sort(id+1,id+n+1,cmp);
          /*id排序见cmp*/
          /*从第一个点(提及次数最少的点)开始寻找*/
        if(dfs(1))  printf("Yes\n");
        else printf("No\n");
        
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值