zoukankan      html  css  js  c++  java
  • 紫书 习题8-9 UVa 1613 (dfs染色+图的性质)

    这道题一开始我没想什么直接开始染, 但是是for循环一个节点一个节点染, 然后就WA

    后了看了https://www.cnblogs.com/jerryRey/p/4702323.html

    发现原来还需要证明一下染色一定可以, 同时染色的方式是dfs

    (1)证明

    首先, 如果最大度数sum是偶数, 那么按照题目意思, k就为sum+1.

    这个时候最坏情况下最大度数点与周围点的颜色都不一样, 需要sum+1种颜色, 也就是刚好是

    k, 所以这种情况一定可以用k种颜色染完

    其次, 如果最大度数sum是奇数的话, 此时k=sum, 最坏情况也是最大度数点与周围点的颜色都不一样。

    但是这种情况可以证明是不存在的, 因为n为奇数

    假设这种情况存在, 那么最大度数点u的一个相邻点v, 那么v一定有degree[u](u的度数)

    个颜色不相同的点在v周围。为什么呢, 如果不是的话, 那么v的颜色就有多种可能

    (没有被周围点限制), 那么就不满足前面所讲的最大度数点与周围点颜色不一样,

    因为v可以为其他颜色。所以v一定有degree[u](u的度数)个颜色不相同的点在v周围。

    那么可以推出u周围所有点都是这样, 同理u周围的点的周围点也是这样。

    所以这个图是个完全图, 也就是说一个点和其他所有节点都可以直接连接。

    那么, 前面说最大度数sum是奇数, 那么图中点的个数为sum+1(本身), 

    也就是点数为偶数。与题目给的n为奇数是矛盾的。

    所以在最大度数sum是奇数这种情况下, 一定不存在最大度数点与周围点的颜色都不一样这

    中情况(此时需要颜色数为sum+1), 也就是说需要颜色一定小于这种情况需要的颜色(需要颜色 < sum + 1) 

    也就是 需要颜色<= sum = k, 所以k种颜色一定可以染完。


    (2)染色方式

    貌似dfs这样染周围的点的方式比较优。我之前用for循环遍历点来染色的方法会把后面的点“堵死”。


    (3)另外, 学到了 a | 1是奇数不变, 偶数加1, 以及max_element的用法, 加上*表示指针的值


    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    #define REP(i, a, b) for(int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 11234;
    vector<int> g[MAXN];
    int degree[MAXN], color[MAXN], vis[MAXN], n, m, k;
    
    void dfs(int u)  //dfs染色 
    {
    	REP(i, 0, g[u].size() - 1)
    		vis[color[g[u][i]]] = u;
    	
    	REP(i, 1, k)
    		if(vis[i] != u)
    		{
    			color[u] = i;
    			break;
    		}
    	
    	REP(i, 0, g[u].size() - 1)
    		if(!color[g[u][i]])
    			dfs(g[u][i]);
    }
    
    int main()
    {
    	while(~scanf("%d%d", &n, &m))
    	{
    		REP(i, 1, n) g[i].clear();
    		memset(degree, 0, sizeof(degree));
    		memset(color, 0, sizeof(color));
    		memset(vis, 0, sizeof(vis));
    		
    		while(m--)
    		{
    			int x, y;
    			scanf("%d%d", &x, &y);
    			g[x].push_back(y);
    			g[y].push_back(x);
    			degree[x]++; degree[y]++;
    		}
    		
    		k = (*max_element(degree+1, degree+n+1)) | 1;	//偶+1, 奇不变。 
    		dfs(1);                                         // max_element求最大值, 返回指针 
    		
    		printf("%d
    ", k);
    		REP(i, 1, n) printf("%d
    ", color[i]);
    		puts("");
    	}
    	
    	return 0;
    }

  • 相关阅读:
    android ndk通过遍历和删除文件
    SVN提交忽略*.class、.classpath、.mymetadata、.project、.settings、.myeclipse和其他非版本控制文件
    JDBC加载过程
    JVMTI 中间JNI系列功能,线程安全和故障排除技巧
    【Python】Python与文本处理langid工具包的文本语言检测和歧视
    SQL 存储过程 分页
    Android:仿手机QQ朋友动态ListView
    再说Java EE
    辛星与您解读PHP页面跳转的几种实现方式
    VS2010 使用TeeChart画图控件
  • 原文地址:https://www.cnblogs.com/sugewud/p/9819573.html
Copyright © 2011-2022 走看看