首页 > 其他分享 >题解:P11409 西湖有雅座

题解:P11409 西湖有雅座

时间:2024-12-18 21:58:06浏览次数:3  
标签:LF return int 题解 雅座 dfs using 1005 P11409

题解:P11409 西湖有雅座

题目转送带

简洁思路

由于数据比较小,可以先预处理出任何两个零件是否能出现在同一栋大楼上。即枚举所有的两个零件,根据题意去模拟判断条件是否满足:

\[\forall i,j \in U,f\left (i,j\right) \ge \lceil \frac{ \min \left ( S\left(i \right),S\left(j\right) \right) }{2} \rceil \]

若不符合则连一条边。然后便可以直接转化为二分图染色问题求解。

关于二分图染色的简洁说明

把二分图中不能处于同一集合的点连一条边,在该边两端染上不同颜色,即 0 和 1 。若出现矛盾则说明不能成立,直接返回。(这只是笔者自己的简洁理解,若要掌握二分图染色还是要自己去找博客系统学习)

code

#include<bits/stdc++.h>
using namespace std;
int n,h,w;
const int N=1005;
int a[1000+5][10][10];
int t[N];
vector<int>g[N];
int k[N];
int s[N];
int ans;
bool dfs(int u,int c){
	k[u]=c;s[c]++;
	for(auto v:g[u]){
		if(k[v]==k[u]) return false;
		if(k[v]==-1&&!dfs(v,1-c)) return false;
	}
	return true; 
}
int main(){
	cin>>n>>h>>w;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=h;j++)
			for(int k=1;k<=w;k++){
				cin>>a[i][j][k];
				t[i]+=a[i][j][k];
			}
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			if(i==j) continue;
			int f=0;
			for(int x=1;x<=h;x++)
				for(int y=1;y<=w;y++){
					f+=a[i][x][y]&&a[j][x][y];
				}
			if(f<(min(t[i],t[j])+1)/2){
				g[i].push_back(j);
				g[j].push_back(i);
			}
		}
	memset(k,-1,sizeof k);
	for(int i=1;i<=n;i++){
		int p0=s[0];
		int p1=s[1];
		if(k[i]==-1&&!dfs(i,1)){
			cout<<-1<<endl;
			return 0;
		}
		ans+=max(s[0]-p0,s[1]-p1);
	}
	cout<<ans<<endl;
	return 0;
}

本题后记

本题为 2024 年 12 月的 [DHOI] Round 1 洛谷比赛中,数据实在过水。同机房的 QC dalao 直接写了个假贪心过了第二和第三个包(难以想象),而 FRZ dalao 则写出了第一个包,于是……
超级缝合怪。

水数据点AC_code

#ifndef ONLINE_JUDGE
#define FRZ_29
#endif

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
//using i128 = __int128;

const int N = 1005;

#define PRINT(x) cout << #x << " = " << x << "\n"
#define LF(i, l, r) for (int i = (l); i <= (r); i++)
#define RF(i, r, l) for (int i = (r); i >= (l); r++)

int n, h, w, s[N], f[N][N];
int m[N][10][10], ans;
vector<int> U;
bool vis[N];

bool check() {
  LF(i, 0, U.size() - 1) {
    LF(j, i + 1, U.size() - 1) {
      if (f[U[i]][U[j]] < (min(s[U[i]], s[U[j]]) + 1) / 2) {
        return false;
      }
    }
  }

  LF(i, 1, n) {
    if (vis[i]) continue;
    LF(j, i + 1, n) {
      if (vis[j]) continue;
      if (f[i][j] < (min(s[i], s[j]) + 1) / 2) return false;
    }
  }

  return true;
}

void dfs(int d) {
  if (d == n + 1) {
    if (check()) ans = max(ans, max((int)(n - U.size()), (int)(U.size())));
    return;
  }

  U.push_back(d);
  vis[d] = 1;
  dfs(d + 1);
  U.pop_back();
  vis[d] = 0;
  dfs(d + 1);
}
int a[1005][15][15];
int sum[1005];//f[1005][1005];
int num[1005][1005];
struct node
{
    int id,s;
}frz[1005];
bool cmp(node x,node y){return x.s<y.s;}
inline int read()
{
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(int)(c-'0');c=getchar();}
    return x*f;
}
inline void write(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline void solve()
{   
//    cin>>n>>h>>w;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=h;j++)
            for(int k=1;k<=w;k++) cin>>a[i][j][k],sum[i]+=a[i][j][k];
    for(int oi=1;oi<=n;oi++)
    {
        for(int oj=1;oj<=n;oj++)
        {
            if(oj==oi) continue;
            for(int i=1;i<=h;i++)
                for(int j=1;j<=w;j++) f[oi][oj]=f[oi][oj]+(a[oi][i][j]&a[oj][i][j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        frz[i].id=i;
        for(int j=1;j<=n;j++)
        {
            // if(i==j) continue;
            // cout<<f[i][j]<<" "<<((min(sum[i],sum[j])+1)/2)<<endl;
            if(f[i][j]<((min(sum[i],sum[j])+1)/2))
            {
                num[i][j]=1;
            }
            frz[i].s+=num[i][j];
        }
    }
    sort(frz+1,frz+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        int kkk=frz[i].id;
        if(vis[kkk]==0)
        {
            ans++;
            for(int j=1;j<=n;j++)
            {
                if(num[kkk][j]==1)
                {
                    vis[j]=1;
                }
            }
        }
    }
    if(ans==1) cout<<-1<<endl;
    else cout<<ans<<endl;

}

int main() {
//#ifdef FRZ_29
//  freopen("code.in", "r", stdin);
//  freopen("code.out", "w", stdout);
//#endif

  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  
  cin >> n >> h >> w;
	if(n>20) {solve();return 0;} 
  LF(i, 1, n) LF(j, 1, h) LF(k, 1, w) {
    cin >> m[i][j][k];
    s[i] += m[i][j][k];
  }

  LF(i, 1, n) LF(j, i + 1, n) LF(k, 1, h) LF(p, 1, w)
    f[i][j] += (m[i][k][p] & m[j][k][p]);
  
  dfs(1);
  cout << (ans == 0 ? -1 : ans);
  return 0;
}


// START AT 2024 / 12 / 15 13 : 56 : 15

水完了。
yingxilin
Qian·JX のjoker
2024-12-18 于玉山一中

标签:LF,return,int,题解,雅座,dfs,using,1005,P11409
From: https://www.cnblogs.com/yingxilin/p/18615924

相关文章

  • 把半年前完全没思路的题解了的感觉真好
    虽然处理了很多次索引思路,不过最后还是过了。第一眼就有解题思路,这种感觉真不错,要的就是这种打怪升级的正反馈。附上解题代码`#@lcapp=leetcode.cnid=2266lang=python3[2266]统计打字方案数@lccode=startfromcollectionsimportCounterfromfunctoolsimportcac......
  • CF1100F题解
    \(CF1100F\),\(Ivan\)\(and\)\(Burgers\)题意:静态序列查询一个区间中选取任意个数的最大异或和,\((n\le10^6)\)\(sol\):考虑离线做,把询问按\(r\)从小到大排序,每次\(r\)右移时把新框进来的数加入线性基中,同时记录线性基每一位在序列中的位置,贪心的考虑显然位置越靠后越优,查......
  • 牛客小白月赛106 题解 更新至 F 题
    Preface期末周闲的没事写一场小白月赛我会在代码一些有必要的地方加上注释,签到题可能一般就不会写了.以下是代码火车头:#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#include<vector>#include<set>#include<queue>#include<map>......
  • tauri2文件资源访问和存储常见问题解决
    上tauri2的github上搜一下,发现问题还是挺多的,如果你是从tauri1迁移过来的话,估计要走的坑更多,因为tauri2的配置很多已经和tauri1不一样了,如果你还是习惯用tauri1的配置思维来搞tauri2的话,肯定会让你很难受。附上tauri2常用的几个链接:官方javascript的api文档:window|Tauri ......
  • [HDU5603] the soldier of love 题解
    考虑到正向求解困难,于是正难则反。那么实际上对于\(a_i\)和\(a_{i+1}\)来说,它们给答案的贡献就是满足\(l_j>a_i,r_j<a_{i+1}\)的区间数量。那么就是经典转化了。直接转换为二维数点问题即可。时间复杂度\(O(tn\logV)\),离散化可以将\(\logV\)转化为\(\logn\)。#inc......
  • CF1889D Game of Stacks 题解
    很有趣的题目.思路我们考虑如果每一个栈里只有一个数怎么办。这个时候,我们会形成一个基环树森林。我们的操作相当于每走一步就删掉来时的路。那么每个点最终会停在离它最近的环上的点。我们可以发现一个性质,一个环是不会影响结果的,因为它总能走回来。所以我们可以不断的删......
  • P7531 [USACO21OPEN] Routing Schemes P 题解
    best定理居然还有运用范围。思路考虑如何来判断是否有解。由于每一条边都需要用到。但是它是使用很多条路径进行覆盖。我们考虑一个很巧妙的转化。建立一个超级源点,源点向每一条路径的开头连一条边。每一条路径的结尾向源点连一条边,这样一条路径就变成了一个回路。把所有......
  • AT_abc129_f [ABC129F] Takahashi's Basics in Education and Learning 题解
    题目传送门前置知识矩阵加速递推解法设\(f_{i}\)表示将\(s_{1}\sims_{i}\)拼起来后的值,状态转移方程形如\(f_{i}=10^{k}f_{i-1}+s_{i}\),其中\(k=\left\lfloor\log_{10}s_{i}\right\rfloor+1\)。又因为保证等差数列中的元素\(\le10^{18}\),对于每个\(k\in[1,......
  • Pinely Round 2 (Div. 1 + Div. 2) / Codeforces contest 1863 题解
    ProblemA.Channelhttps://codeforces.com/contest/1863/problem/A流程看起来很复杂,让我们重述一下题意。两数\(x\),\(y\)。\(opt1\),你可以选\(x\)和\(y\)当中某个非零的,减少\(1\)。\(opt2\),让\(x\)增加\(1\)。\(Q1:\)是否可以让\(y\)变成\(0\),$Q2:$......
  • AT_agc032_d [AGC032D] Rotation Sort 题解
    考虑确定哪些点不动,这些点一定构成一个单调递增子序列,那么对于剩下的点:若在它之前存在一个不动点大于它,则需要花费\(b\)的代价向前移动。若在它之后存在一个不动点小于它,则需要花费\(a\)的代价向后移动。如果两个都不存在,则它一定可以加入不动点序列。考虑dp,记\(f_{i,......