[TCO2009]NumberGraph
题意:给你一些带权的节点和一个正整数集合$S$,$S$中每一个数的二进制后缀$0$个数相同,节点$x$的权值为$v_x$,如果对于$x,y$存在$t\in S$使得$|v_x-v_y|=t$,那么连边$(x,y)$,现在要找出一个最大的子图使得子图中的节点两两最短距离$\leq2$
第一次用TC客户端上的Arena,特别开心==
如果$S$中每个数末尾有$k$个$0$,那么一条边的两个端点的权值的第$k+1$位必定不同,所以这个图是二分图
接下来相当于是要在二分图的两部分中分别找一个非空点集,使得两个集合中的点两两有边相连,对两部间的边取补后问题变为两两无边相连
因为要求非空所以不能直接跑最大独立集,考虑枚举一对不相邻的,分属二分图两部的节点,硬点他们必须被选,删掉它们和与之相连的边,对剩下的点跑最大独立集即可
#include<vector>
#include<string>
#include<sstream>
#include<algorithm>
#include<string.h>
using namespace std;
const int inf=2147483647;
int lowbit(int x){return x&-x;}
int abs(int x){return x>0?x:-x;}
string str;
int h[90],nex[5010],to[5010],cap[5010],M,S,T;
void ins(int a,int b,int c){
M++;
to[M]=b;
cap[M]=c;
nex[M]=h[a];
h[a]=M;
}
void add(int a,int b,int c){
ins(a,b,c);
ins(b,a,0);
}
int dis[90],q[90];
bool bfs(){
int head,tail,x,i;
memset(dis,-1,sizeof(dis));
head=tail=1;
q[1]=S;
dis[S]=0;
while(head<=tail){
x=q[head++];
for(i=h[x];i;i=nex[i]){
if(cap[i]&&dis[to[i]]==-1){
dis[to[i]]=dis[x]+1;
if(to[i]==T)return 1;
q[++tail]=to[i];
}
}
}
return 0;
}
int cur[90];
int dfs(int x,int flow){
if(x==T)return flow;
int us=0,i,t;
for(i=cur[x];i&&flow;i=nex[i]){
if(cap[i]&&dis[to[i]]==dis[x]+1){
t=dfs(to[i],min(flow,cap[i]));
cap[i]-=t;
cap[i^1]+=t;
us+=t;
flow-=t;
if(cap[i])cur[x]=i;
}
}
if(us==0)dis[x]=-1;
return us;
}
int dicnic(){
int ans=0;
while(bfs()){
memcpy(cur,h,sizeof(h));
ans+=dfs(S,inf);
}
return ans;
}
bool g[90][90];
int v1[90],v2[90],d[90],n1,n2,lw,cnt;
int gao(int x,int y){
int i,j,sum;
cnt++;
d[x]=cnt;
for(i=1;i<=n2;i++){
if(g[x][i])d[i+n1]=cnt;
}
d[y+n1]=cnt;
for(i=1;i<=n1;i++){
if(g[i][y])d[i]=cnt;
}
memset(h,0,sizeof(h));
M=1;
sum=0;
for(i=1;i<=n1;i++){
if(d[i]!=cnt){
add(S,i,1);
sum++;
}
}
for(i=n1+1;i<=n1+n2;i++){
if(d[i]!=cnt){
add(i,T,1);
sum++;
}
}
for(i=1;i<=n1;i++){
if(d[i]!=cnt){
for(j=n1+1;j<=n1+n2;j++){
if(g[i][j-n1]&&d[j]!=cnt){
add(i,j,1);
}
}
}
}
return sum-dicnic()+2;
}
class NumberGraph{
public:
int largestSet(vector<string>gs,vector<int>js){
int x,i,j,k,ans;
bool flag;
str="";
for(i=0;i<(int)gs.size();i++)str+=gs[i];
istringstream cin(str);
lw=lowbit(js[0]);
n1=n2=0;
while(cin>>x)(x&lw?v1[++n1]:v2[++n2])=x;
S=n1+n2+1;
T=S+1;
for(i=1;i<=n1;i++){
for(j=1;j<=n2;j++){
flag=1;
for(k=0;k<(int)js.size();k++){
if(abs(v1[i]-v2[j])==js[k]){
flag=0;
break;
}
}
g[i][j]=flag;
}
}
ans=1;
for(i=1;i<=n1;i++){
for(j=1;j<=n2;j++){
if(!g[i][j])ans=max(ans,gao(i,j));
}
}
return ans;
}
};
/*
int main(){
NumberGraph g;
vector<string>vs;
vector<int>vi;
string s;
int x;
ostringstream os;
scanf("%d",&x);
while(x){
os<<x<<' ';
scanf("%d",&x);
}
vs.push_back(os.str());
scanf("%d",&x);
while(x){
vi.push_back(x);
scanf("%d",&x);
}
printf("%d",g.largestSet(vs,vi));
}
*/
[TCO2009]NumberGraph的更多相关文章
随机推荐
- 消息队列之 ActiveMQ(山东数漫江湖)
简介 ActiveMQ 特点 ActiveMQ 是由 Apache 出品的一款开源消息中间件,旨在为应用程序提供高效.可扩展.稳定.安全的企业级消息通信. 它的设计目标是提供标准的.面向消息的.多语言 ...
- [IOS]VMware上虚拟机MAC安装XCode
1:VMware上虚拟机MAC安装前 VMware上安装Xcode之后 2:安装Xcode过程:把Xcode复制到虚拟机桌面上 3:复制完成之后,双击Xcode_6.4.dmg 文件 4:把Xcode ...
- vue数组操作不触发前端重新渲染
暂时使用给数组先赋值 [ ] ,然后重新赋值的方式解决. 此外,能够监听的数组变异方法 https://cn.vuejs.org/v2/guide/list.html#%E5%8F%98%E5%BC% ...
- Python 用ctypes观察Python对象的内存结构 -- (转)
!!!强烈推荐的好文章!!! 对象的两个基本属性 Python所有对象结构体中的头两个字段都是相同的: refcnt:对象的引用次数,若引用次数为0则表示此对象可以被垃圾回收了. typeid:指向描 ...
- Linux 入门记录:十六、Linux 多命令协作:管道及重定向
一.多命令协作 在 Linux 系统当中,大多数命令都很简单,很少出现复杂功能的命令,每个命令往往只实现一个或多个很简单的功能.通过将不同功能的命令组合一起使用,可以实现某个复杂功能的. Linux ...
- 用vue实现登录页面
vue和mui一起完成登录页面(在hbuilder编辑器) <!DOCTYPE html> <html> <head> <meta charset=" ...
- Shell——Linux/Mac 终端复制文件内容到剪切板
pbcopy < filename 如: pbcopy < README.md 效果如下: 说明:上图中 # gitskills 即README.md 中内容.
- Geoserver发布缓存切片(制定Gridsets)
EPSG:4326 Level Pixel Size Scale Name Tiles 0 1: 2 x 1 1 1: 4 x 2 2 1: 8 x 4 3 1: 16 x 8 4 ...
- 创建.dat文件(转载)
比较有用的东比较有用的东西 首先,批处理文件是一个文本文件,这个文件的每一行都是一条DOS命令(大部分时候就好象我们在DOS提示符下执行的命令行一样),你可以使用DOS下的Edit或者Windows的 ...
- visualvm监控远程机器上的Java程序
源文:http://hanwangkun.iteye.com/blog/1195526