CF60C Mushroom Strife 解题报告

CF60C Mushroom Strife 解题报告

1 题目链接

https://codeforces.com/problemset/problem/60/C

2 题目整理

题目 :蘑菇冲突

题目描述

帕夏和阿基姆正在绘制一张地图——草坪是地图的顶点,连接草坪的道路是地图的边。他们决定用以下方式对每片草坪上的蘑菇数量进行编码:在两片草坪之间的每一条边上,他们写下两个数字,即这些草坪上蘑菇数量的最大公约数(GCD)和最小公倍数(LCM)。但有一天,帕夏和阿基姆就这些蘑菇发生了争执,并撕毁了地图。帕夏只剩下一部分,只有m条路。你的任务是帮助帕夏——利用他拥有的地图恢复每片草坪上蘑菇的数量。由于结果不一定是唯一的,请帮助帕夏恢复任何一种蘑菇,或报告这种蘑菇排列不存在。保证初始地图上的道路数量不少于1,且不超过 1 0 6 10^6 106

输入格式

第一行包含两个数字n和m,这是我们知道的草坪和道路的数量。下面m组数据中每一组包含四个数字,即道路连接的草坪数量、这些草坪上蘑菇数量的最大公因数和最小公倍数。

可以保证的是,没有任何道路将草坪连接到自身,也没有两个草坪通过一条以上的道路连接。

输出格式

答案的第一行应是“YES”或“NO”,说明是否可能执行该安排。如果答案是“YES”,请在下一行打印相应草坪上蘑菇的数量。

样例输入1
1 0
样例输出1
YES
1
样例输入2
2 1
1 2 1 3
样例输出2
YES
1 3
样例输入3
3 2
3 2 1 2
3 1 1 10
样例输出3
YES
5 1 2
样例输入4
2 1
1 2 3 7

样例输出4
NO
数据范围

对于 100 % 100\% 100%的数据:
1 ≤ n ≤ 100 1 \le n \le 100 1n100
1 ≤ m ≤ n × ( n + 1 ) 2 1 \le m \le \frac{n \times (n + 1)}{2} 1m2n×(n+1)
1 ≤ G C D , L C M ≤ 1 0 6 1 \le GCD, LCM \le 10^6 1GCDLCM106

3 题意分析

3.1 题目大意

给定一个n个点,m条边的无向图,每个点上有一个数值,每条边上标记着它连接的两个点的GCD和LCM。请给出一种点上的数值的构造。若没有,输出 " N O " "NO" "NO",否则 “ Y E S ” “YES” YES加构造

3.2 样例分析

如上所述。

4 解法分析

先考虑数据范围,n小于100,所以题目应该可以用暴力或深搜来做。再分析题目。有公式: a × b = G C D ( a , b ) ∗ L C M ( a , b ) a \times b = GCD(a,b) * LCM(a,b) a×b=GCD(a,b)LCM(a,b),所以只要确定了a,就能推出b。类似的,只要确定一个连通快里的一个数,就能推出此连通块内的所有数。那么,我们可以先枚举其中一个数,再推出其他的数,看可不可行。这样,整道题就轻松了许多。

AC代码

ACCode #001
// From nvmdava
// Rating 2447
// reason : 思路清晰,代码简洁易懂
#include <bits/stdc++.h>
using namespace std;

struct Edge{
	int to;
	long long gcd, lcm;
	Edge(int _u, int _gcd, int _lcm){
		to = _u;
		gcd = _gcd;
		lcm = _lcm;
	}
};

vector<Edge> to[105];
long long a[105];

void clr(int v){
	a[v] = 0;
	for(auto x : to[v])
		if(a[x.to])
			clr(x.to);
}

bool dfs(int v){
	for(auto x : to[v]){
		if(a[x.to]){
			if(__gcd(a[v], a[x.to]) != x.gcd) return 0;
			if(a[v] * a[x.to] != x.lcm * x.gcd) return 0;
			continue;
		}
		a[x.to] = x.lcm * x.gcd / a[v];
		if(a[x.to] <= 0 || a[x.to] > 1000000) return 0;
		if(__gcd(a[v], a[x.to]) != x.gcd) return 0;
		if(a[v] * a[x.to] != x.lcm * x.gcd) return 0;
		if(!dfs(x.to)) return 0;
	}
	return 1;
}

int main(){
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	int n, m;
	cin>>n>>m;
	while(m--){
		int v, u, g, l;
		cin>>v>>u>>g>>l;
		to[v].push_back(Edge(u, g, l));
		to[u].push_back(Edge(v, g, l));
	}
	
	for(int i = 1; i <= n; i++){
		if(a[i]) continue;
		for(int j = 1; j <= 1000000; j++){
			a[i] = j;
			if(!dfs(i)) clr(i);
			else break;
		}
		
		if(!a[i]){
			cout<<"NO";
			return 0;
		}
	}
	cout<<"YES\n";
	for(int i = 1; i <= n; i++)
		cout<<a[i]<<' ';
}
ACCode #002
// From rng_58
// Rating 3074
// reason : 代码简洁明了清晰,
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>

using namespace std;

#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
#define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)

typedef long long ll;

int N;
ll a[110][110],b[110][110]; // gcd, lcm
ll c[110];

ll gcd(ll x, ll y){
    return x ? gcd(y%x,x) : y;
}

bool dfs(int p, ll x){
    int i;
    if(c[p] != 0 && c[p] != x) return false;
    if(c[p] != 0) return true;
    c[p] = x;
    REP(i,N) if(a[p][i] > 0){
        if(a[p][i] * b[p][i] % c[p] != 0) return false;
        ll y = a[p][i] * b[p][i] / c[p];
        if(gcd(c[p],y) != a[p][i]) return false;
        if(!dfs(i,y)) return false;
    }
    return true;
}

void clear(int p){
    int i;
    if(c[p] == 0) return;
    c[p] = 0;
    REP(i,N) if(a[p][i] > 0) clear(i);
}

int main(void){
    int i,j,E,x,y,_a,_b;
    
    scanf("%d%d",&N,&E);
    REP(i,E){
        scanf("%d%d%d%d",&x,&y,&_a,&_b); x--; y--;
        a[x][y] = a[y][x] = _a; b[x][y] = b[y][x] = _b;
    }
    
    bool failed = false;
    REP(i,N) if(c[i] == 0){
        REP(j,N) if(b[i][j] != 0) break;
        if(j == N) {c[i] = 1; continue;}
        
        bool flag = false;
        for(x=1;x*x<=b[i][j];x++) if(b[i][j]%x == 0){
            if(dfs(i,x)) {flag = true; break;} clear(i);
            if(dfs(i,b[i][j]/x)) {flag = true; break;} clear(i);
        }
        
        if(!flag) {failed = true; break;}
    }
    
    if(failed){
        cout << "NO" << endl;
    } else {
        cout << "YES" << endl;
        REP(i,N){
            cout << c[i];
            if(i == N-1) cout << endl; else cout << ' ';
        }
    }
    
    return 0;
}

ACCode #003
// From KrK
// Rating 2787
// reason : 思路清晰,代码简单易懂,可读性强
#include <iostream>
#include <vector>
using namespace std;

const int Maxn = 101;
const int Inf = 1000001;

int n, m, num[Maxn];
vector <int> neigh[Maxn], g[Maxn], l[Maxn];
bool del[Maxn], taken[Maxn], stop;

int gcd(int x, int y)
{
    while (x != 0) {
          int tmp = y % x;
          y = x;
          x = tmp;
    }
    return y;
}

void Search(int v)
{
     int i;
     for (i = 0; i < neigh[v].size() && !stop; i++)
        if (num[v] % g[v][i] || l[v][i] % num[v]) stop = true;
        else {
             int newnum = l[v][i] / num[v] * g[v][i];
             if (gcd(newnum, num[v]) != g[v][i] || 
                 num[neigh[v][i]] && num[neigh[v][i]] != newnum) stop = true;
             else if (num[neigh[v][i]]) continue;
             else {
                  num[neigh[v][i]] = newnum;
                  Search(neigh[v][i]);
             }
        }
}

void DFS(int v)
{
     if (del[v]) return;
     del[v] = true;
     for (int i = 0; i < neigh[v].size(); i++)
        DFS(neigh[v][i]);
}

void SwitchBack(int v)
{
     if (num[v] == 0) return;
     num[v] = 0;
     for (int i = 0; i < neigh[v].size(); i++)
        SwitchBack(neigh[v][i]);
}

int main()
{
    int a, b, c, d;
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        cin >> a >> b >> c >> d;
        neigh[a].push_back(b); g[a].push_back(c); l[a].push_back(d);
        neigh[b].push_back(a); g[b].push_back(c); l[b].push_back(d);
    }
    int i;
    for (i = 1; i <= n; i++) if (!del[i]) {
        int j;
        for (j = 1; j < Inf; j++) {
            stop = false;
            num[i] = j;
            Search(i);
            if (!stop) break;
            SwitchBack(i);
        }
        if (j == Inf) break;
        DFS(i);
    }
    if (i <= n) cout << "NO\n";
    else {
         cout << "YES\n";
         for (int i = 1; i <= n; i++) {
             if (i > 1) cout << " ";
             cout << num[i];
         }
         cout << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值