和以前写过的一道题很像,感谢当初自己还去回顾了一下,看到这个结构就能理解个大概,代码倒是不难理解,都没用草稿纸,脑子里就有结果,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");
}
}