hdu 5313
题意:给你一个二分图,然后问你最多加多少边能变成完全二分图
题解:先dfs染色,求出每个子图中的黑白的个数,然后应该就是dp,每个子图取黑色或白色,最后二分图两边的点为x和y,x+y=n,然后求x×y最大
然而这题不满足dp的复杂度,百度了个bitset,看着挺好用的样子,不过手残写错了几次。
然后题目里说有重边,也不知道他到底有没有,直接减去m也对
bitset:
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <bitset> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 10005 #define MAXN 2000005 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define mid int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem0(x) memset(x,0,sizeof(x)) #define mem1(x) memset(x,-1,sizeof(x)) #define meminf(x) memset(x,INF,sizeof(x)) #define lowbit(x) (x&-x) const LL mod = 1000000; const int prime = 999983; const int INF = 0x3f3f3f3f; const int INFF = 1e9; const double pi = 3.141592653589793; const double inf = 1e18; const double eps = 1e-10; /**************读入外挂**********************/ inline int read_int(){ int ret=0; char tmp; while(!isdigit(tmp=getchar())); do{ ret=(ret<<3)+(ret<<1)+tmp-'0'; }while(isdigit(tmp=getchar())); return ret; } /*******************************************/ struct Edge{ int v,next; }edge[200005]; struct cha{ int a,b; bool operator < (const cha &e)const{ return a-b>e.a-e.b; } }p[MAX]; int head[MAX]; int col[MAX]; int num1[MAX]; int num2[MAX]; set<int> s[MAX]; int tot; int cnt; int n,m; int sum1,sum2; void add_edge(int a,int b){ edge[tot]=(Edge){b,head[a]}; head[a]=tot++; } void init(){ mem1(head); mem0(col); mem0(num1); mem0(num2); tot=0; cnt=0; for(int i=1;i<=n;i++) s[i].clear(); } void dfs(int u){ for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(!col[v]){ col[v]=-col[u]; if(col[v]==1) sum1++; else sum2++; dfs(v); } } } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); init(); int tmp=0; for(int i=1;i<=m;i++){ int a,b; scanf("%d%d",&a,&b); add_edge(a,b); add_edge(b,a); if(s[a].count(b)) continue; tmp++; s[a].insert(b); s[b].insert(a); } for(int i=1;i<=n;i++){ if(!col[i]){ sum1=1; sum2=0; col[i]=1; dfs(i); p[cnt++]=(cha){max(sum1,sum2),min(sum1,sum2)}; } } bitset<10001> bi; bi.set(0); for(int i=0;i<cnt;i++){ bi=bi<<p[i].a|bi<<p[i].b; } for(int i=n/2;i>0;i--){ if(bi[i]){ printf("%d\n",i*(n-i)-tmp); break; } } } return 0; }
然后感觉贪心貌似也可以啊,一个子图里面黑色a,白色b个,然后先按照每个子图黑白之差排序,然后二分图的两侧,少的那一侧就加子图多的那部分点
感觉应该也没问题啊虽然百度说可能有错,但是也能AC
贪心还是要敢于写,毕竟这题dp TLE的概率远大于贪心WA的概率
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <bitset> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 10005 #define MAXN 2000005 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define mid int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem0(x) memset(x,0,sizeof(x)) #define mem1(x) memset(x,-1,sizeof(x)) #define meminf(x) memset(x,INF,sizeof(x)) #define lowbit(x) (x&-x) const LL mod = 1000000; const int prime = 999983; const int INF = 0x3f3f3f3f; const int INFF = 1e9; const double pi = 3.141592653589793; const double inf = 1e18; const double eps = 1e-10; /**************读入外挂**********************/ inline int read_int(){ int ret=0; char tmp; while(!isdigit(tmp=getchar())); do{ ret=(ret<<3)+(ret<<1)+tmp-'0'; }while(isdigit(tmp=getchar())); return ret; } /*******************************************/ struct Edge{ int v,next; }edge[200005]; struct cha{ int a,b; bool operator < (const cha &e)const{ return a-b>e.a-e.b; } }p[MAX]; int head[MAX]; int col[MAX]; int num1[MAX]; int num2[MAX]; set<int> s[MAX]; int tot; int cnt; int n,m; int sum1,sum2; void add_edge(int a,int b){ edge[tot]=(Edge){b,head[a]}; head[a]=tot++; } void init(){ mem1(head); mem0(col); mem0(num1); mem0(num2); tot=0; cnt=0; for(int i=1;i<=n;i++) s[i].clear(); } void dfs(int u){ for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(!col[v]){ col[v]=-col[u]; if(col[v]==1) sum1++; else sum2++; dfs(v); } } } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); init(); int tmp=0; for(int i=1;i<=m;i++){ int a,b; scanf("%d%d",&a,&b); add_edge(a,b); add_edge(b,a); if(s[a].count(b)) continue; tmp++; s[a].insert(b); s[b].insert(a); } for(int i=1;i<=n;i++){ if(!col[i]){ sum1=1; sum2=0; col[i]=1; dfs(i); p[cnt++]=(cha){max(sum1,sum2),min(sum1,sum2)}; } } bitset<10001> bi; bi.set(0); for(int i=0;i<cnt;i++){ bi=bi<<p[i].a|bi<<p[i].b; } for(int i=n/2;i>0;i--){ if(bi[i]){ printf("%d\n",i*(n-i)-tmp); break; } } } return 0; }