首页 > 其他分享 >带权拟阵交

带权拟阵交

时间:2023-11-20 22:00:09浏览次数:19  
标签:cnt ll return int 拟阵 item 带权 col

'''cpp

include<bits/stdc++.h>

include

using namespace std;
const int N = 505;
int n , m;
map<int,vector<pair<int,int>>>E;
map<int,int>limit;
typedef long long ll;
struct uni {
int p[N];
int cnt ;
void init() {
for(int i = 1; i <= n; i++) p[i] = i;
cnt = n;
}
int Find(int x) {
return p[x] == x ? x : p[x] = Find(p[x]) ;
}
bool Merge(int u,int v) {
u = Find(u) , v = Find(v);
if(u == v) return 0;
p[u] = v;
cnt--;
return 1;
}
bool in(int u,int v) {
return Find(u) == Find(v);
}
} Un[N];
struct edge {
int u , v , w;
};
struct Item {
int x,y,col;
ll val;
Item() {}
Item(int _x,int _y,int _col,ll _val) {
x=_x;
y=_y;
col=_col;
val=_val;
}
};
namespace Matroid {
///F1 : connect
///F2 : num limit
const int M=N2,E=100005;
const ll inf=1e9;
int n,tot,ans,S,T,g[M],v[E],nxt[E],ed,q[E],h,t,d[M],pre[M],w[M];
map<int,int>cnt;
bool in[M],use[M];
Item item[M];
inline void add(int x,int y) {
v[++ed]=y;
nxt[ed]=g[x];
g[x]=ed;
}
inline void ext(int x,int y,int z) {
if(d[x]>=y)return;
d[x]=y;
pre[x]=z;
if(in[x])return;
q[++t]=x;
in[x]=1;
}
inline bool find() {
int i,j,S=n+1,T=n+2;
for(ed=i=0; i<=T; i++)g[i]=w[i]=0;
for(int i = 0; i < n; i++) {//维护所有的I+{x}
if(!use[i]) {
Un[i].init() ;
for(int j = 0; j < n; j++) {
if(i != j&&(!use[j])) Un[i].Merge(item[j].x , item[j].y);
}
}
}
for(i=0; i<n; i++)if(!use[i]) {
w[i]=item[i].val;
use[i]^=1;
cnt[item[i].col]++;
if(Un[i].cnt == 1)add(S,i);//I+{i}\in F1
if(cnt[item[i].col]<=limit[item[i].col])add(i,T);//I+{i}\in F2
cnt[item[i].col]--;
use[i]^=1;
} else w[i]=-item[i].val;
for(i=0; i<n; i++)if(use[i])for(j=0; j<n; j++)if(!use[j]) {
use[i]=1,use[j]=1;
cnt[item[i].col]--;
cnt[item[j].col]++;
if(Un[j].cnt == 1 || (Un[j].cnt == 2 && (!Un[j].in(item[i].x,item[i].y))))add(i,j);//I-{i}+{j}\in F1
if(cnt[item[j].col]<=limit[item[j].col])add(j,i);//I-{i}+{j}\in F2
cnt[item[i].col]++;
cnt[item[j].col]--;
use[i]=1,use[j]=1;
}
for(i=0; i<=T; i++)d[i]=-inf,in[i]=0;
q[h=t=1]=S;
d[S]=0,in[S]=1;
while(h<=t) {
int x=q[h++];
for(i=g[x]; i; i=nxt[i])ext(v[i],d[x]+w[v[i]],x);
in[x]=0;
}
if(d[T]==-inf)return 0;
ans+=d[T];
while(pre[T]!=S) {
T=pre[T];
if(use[T])cnt[item[T].col]--;
else cnt[item[T].col]++;
use[T]^=1;
}
return 1;
}
inline int intersection(const vector&pool,int _tot) {//finished
int i;
n=ans=0;
tot=_tot;
for(i=0; i<pool.size(); i++) {
item[n++]=pool[i];
}
// for(i=0; i<pool.size(); i++)item[n++]=pool[i];
cnt.clear();
for(i=0; i<n; i++)use[i]=0;
for(i=0; i<tot; i++)if(!find())return -1;
return ans;
}
}
vectoredge_S;
bool chk(ll lm) {//finished
limit.clear();
int sum = 0;
for(auto it = E.begin(); it != E.end(); ++it) {
const int& w = it->first;
const vector<pair<int, int>>& v = it->second;
limit[w] = max(0LL, (ll)v.size() - lm / (ll)w);
sum += limit[w];
}
if(Matroid::intersection(edge_S,sum)!=-1)return 1;
else return 0;
}
int t;
void solve() {//finished
cin >> n >> m;
E.clear();
edge_S.clear();
ll r = 0;
for(int i = 1; i <= m; i++) {
int u , v , w;
cin >> u >> v >> w;
E[w].push_back(pair<int,int> {u , v});
r = max(r , (ll)(1LL
wE[w].size()));
edge_S.push_back(Item(u,v,w,1));
// if(t54&&i1)cout<<u<<" "<<v<<" "<<w<<'\n';
}
ll l = 1;
while(l < r-1) {
ll md = ((l + r) >> 1);
if(chk(md)) {
r = md;
} else {
l = md+1;
}
}
if(chk(l))
cout << l << '\n';
else cout<<r<<'\n';
// cout<<n<<" "<<m<<'\n';
}
int main() {//finished
// freopen("01.in","rt",stdin);
// freopen("01.out","wt",stdout);
ios::sync_with_stdio(false) ;
cin.tie(0) ;
cout.tie(0);
cin >> t;
while(t--) {
solve();
}
cout<<clock();
return 0;
}
/

3
4 4
1 2 1
2 3 1
3 4 2
4 1 2
5 6
1 2 2
2 3 1
1 5 3
1 2 1
4 5 2
4 3 3
2 2
1 2 10
2 1 1
*/
'''

标签:cnt,ll,return,int,拟阵,item,带权,col
From: https://www.cnblogs.com/thedreammaker/p/17845008.html

相关文章

  • 带权并查集
    很新奇啊这个东西。用来解决形如\(x_i-x_j=y\)系列方程组有无解的问题。思路很简单,\(dis_i\)代表从\(i\)的祖先与\(i\)之间的差值。这样能秒算出方程组中任意两个点的差值。本质是每次把两个方程组合并。找祖先部分:intfindpa(intx){ if(fa[x]!=x){ int......
  • 并查集拓展——种类并查集&带权并查集
    在所面临的问题中,我们不仅需要知道两个元素之间是否存在关系,还需要记录其他要素,于是我们需要对原来的并查集进行拓展。种类并查集对于一般的并查集,只能表示“朋友的朋友就是朋友这种关系”,即我们只关系元素之间的连通性问题。但是对于“敌人的敌人就是朋友”这种关系则无能为力......
  • [HNOI2010] 平面图判定-平面图性质、带权并查集/2-sat
    [HNOI2010]平面图判定-平面图性质、带权并查集/2-sathttps://www.luogu.com.cn/problem/P3209题意:给一张\(n\)个点,\(m\)条边的哈密顿图,并且哈密顿回路已知,问是否是平面图,\(T\)组询问。\(1\leqT\leq100,1\leqn\leq200,1\leqm\leq10^4\)。转换挺奇妙的。极大平面......
  • 动态规划——带权二分优化DP 学习笔记
    动态规划——带权二分优化DP学习笔记引入带权二分其实并不一定用于优化DP,也可能用于优化贪心等最优化的算法。带权二分也叫WQS二分,最初由王钦石在他的2012年国家集训队论文中提出。定义使用情况要解决一个最优化问题(求最大/最小值)有一个限制,一般是某个参数要求一......
  • poj 1182 食物链---带权值的并查集
    这题就一组数据,用while(scnaf(“%d%d”,&n,&m)!=EOF)..就wa了,我wa了数次,无语了。。带权值的并查集,d[]数组存的是每个点和根节点的关系,同类为d[i]=0; 根节点吃i点为d[i]=1; i点吃根节点为d[i]=2;自己画图感受一下吧!!#include<stdio.h>#include<string.h>#include<stdlib.h>in......
  • (测试)带权并查集
    带权并查集普通的并查集只能维护每个节点所在集合的编号,带权并查集则可以维护集合内任意一点到所在集合根的距离。带权并查集是结点存有权值信息的并查集。相比于一般的并查集,带权并查集需要开辟两个数组:一个是dsu[N],用来判断集合关系;一个是dis[N],用来描述其与根节点的关系。当......
  • The Third Letter带权并查集
    Problem-1850H-Codeforces题意是给你a,b,c说明a在b后面c个单位(c<0就是在左边),每个位置只能有一个数,一共有n个位置,告诉你m个关系,问是否符合条件我们可以设置d[x]表示x到它的最早的父节点的距离,然后如果两个数父节点一样,那么c!=d[a]-d[b]时就说明不符合条件那么对于并查......
  • 并查集和带权并查集原理分析
    并查集是算法竞赛中常用的一种数据结构。它可以高效地处理集合之间的操作与询问。其主要功能是查询两个元素是否在同一个集合以及将两个集合合并。第一部分并查集的基本操作算法思想我们将所有元素建成很多棵树(森林),每一棵树就是一个集合。因为并查集是一个树结构,那么每......
  • WQS二分/带权二分/凸包优化
    WQS二分/带权二分/凸包优化应用范围限制个数:给定一些物品和选物品的限制条件,要求刚好选\(m\)个,让你最大化(最小化)权值。单调性:选的物品越多,权值越大(越小)。分析1.原理解释:假设限制不固定,当选\(x\)个时,最大权值为\(f(x)\)。算法的核心就是将“选取物品”这一操作赋......
  • [数据结构]笛卡尔树、ST表、带权并查集
    Cartesiantree(笛卡尔树)1.概念比如拿最小的当根建树,中序遍历是原数组2.性质区间最小值(RMQ),LCA的值,比如上图4和6的LCA是2,表示我们4,6,2这个区间里面的最小值是2找y左边第一个<=y的数就是y往上看第一个向左拐的数3.构造(增量法)对每个前缀考虑我们发现只有右链是......