g_2 + g_3
来源:互联网 发布:程序员 博客 编辑:程序博客网 时间:2024/06/05 01:03
g_2
二分染色 + DP
染色后的题大概就是
先计算出n对数字的和sum
在n对数字中从每一对中选一个数字,然后计算这n个数的和tot
让sum-tot 和tot的差值绝对值最小
这部分可以背包dp和另一种
dp[i][j] = 1表示存在选了前i个数字中差异为j的情况
然后代码中注释写了接下来的操作=_=
注意差值为负数要修正到正数
/*poj1112*/#include <set>#include <cstring>#include <algorithm>#include <iostream>#include <cstdio>#include <cmath>#include <vector>#define mp make_pair#define pb push_back#define X first#define Y secondusing namespace std;typedef long long LL;const int maxn = 105;int n, m, flag;bool vis[maxn], dp[maxn][2 * maxn];int data[maxn][2];int color[maxn];set<int> S[maxn][2];vector<int>E[maxn];struct rd { int diff[maxn * 2];} road[maxn];void dfs(int u, int k, int t) { if(flag == -1) return ; color[u] = k; for(int i = 0; i < E[u].size(); i++) { int v = E[u][i]; if(color[v] == 0) dfs(v, k % 2 + t, t); else if(color[v] == k) flag = -1; }}void solve() { int tot = 1; memset(vis, 0, sizeof vis); for(int i = 1; i <= n; i++) if(color[i] == 0) { dfs(i, tot, tot); tot += 2;//tot/2个连通分量 } //cout<<color[i]<<endl; if(flag == -1) { puts("No solution"); return ; } /** 将这些分成二分图,注意有多个连通分量 然后存每个连通分量的结点,分别保存在S[][0],S[][1]中 将结点个数存在data[][] 对结点个数进行DP DP[i][j] == 1表示选了前i个时差值为j 所以如果DP[i-1][j] == 1,DP[i][j+x-y]和DP[i][j+y-x]也为1 保存路径的时候倒过来想即可 **/ for(int i = 1; i <= n; i++) { S[(color[i] + 1) / 2][color[i] & 1].insert(i); //cout<<(color[i]+1)/2<<endl; } for(int i = 1; i <= tot / 2; i++) { data[i][0] = S[i][0].size(); data[i][1] = S[i][1].size(); // cout<<data[i][0]<<" "<<data[i][1]<<endl; } dp[0][100] = 1; for(int i = 1; i <= tot / 2; i++) for(int j = 0; j <= 200; j++) if(dp[i - 1][j]) { int x = data[i][0], y = data[i][1]; dp[i][j + x - y] = 1; road[i].diff[j + x - y] = 0; dp[i][j + y - x] = 1; road[i].diff[j + y - x] = 1; //cout<<i<<": "<<j + x - y <<" "<<abs(j + y - x)<<endl; } int mn = 1e8, s = -1; for(int j = 0; j <= 200; j++) if(dp[tot / 2][j]) { if(abs(j - 100) < mn) { mn = abs(j - 100); s = j; } } vector<int> Q; Q.clear(); LL cnt = 0; for(int i = tot / 2; i >= 1; i--) { int k = road[i].diff[s]; set<int>::iterator it; for(it = S[i][k].begin(); it != S[i][k].end(); it++) Q.push_back(*it); s -= data[i][k] - data[i][1 - k]; } cout << Q.size(); memset(vis, 0, sizeof vis); for(int i = 0; i < Q.size(); i++) { cout << " " << Q[i]; vis[Q[i]] = 1; } puts(""); cout << n - Q.size(); for(int i = 1; i <= n; i++) if(!vis[i]) cout << " " << i; puts("");}void init() { scanf("%d",&n);//cin会超时 flag = 1; for(int i = 1; i <= n; i++) { vis[i] = 1; for(int j = 1; j <= n; j++) { int x; scanf("%d",&x); if(!x) break; vis[x] = 1; } for(int j = 1; j <= n; j++) if(!vis[j]) { E[i].push_back(j); E[j].push_back(i); } memset(vis, 0, sizeof vis); } solve();}int main() {#ifdef LOCAL freopen("in.txt", "r", stdin);#endif // LOCAL /** 题意:n个人,每个人都想和某些人一起,将n个人分成两组,两组的人数差最小是多少,输出每个组的人 二分染色 + DP **/ init(); return 0;}
g_3
第一道:给m个条件
l,r,x在[l,r]中至少选x个整数
然后问在全部区间内选的最少整数是多少
题解看代码注释部分
第二道
有n个点,
给了m条有向边,问
1.至少选几个点可以走完全部点
可以缩点(去环)后求一下有多少个入度为0的点,选这些点即可
2.至少添加多少条边使整幅图强连通
计算入度为0的点的个数a和出度为0的点个数b
将max(a,b)全部连上min(a,b)上的点,就能强连通
答案输出max(a,b)即可
不过要特判强连通分支只有一个的时候
因为这时不用连边
还有一道网络流不会,学了再补-_-
/*poj 1201*/#include <set>#include <cstring>#include <algorithm>#include <iostream>#include <cstdio>#include <cmath>#include <queue>#include <vector>#define mp make_pair#define pb push_back#define X first#define Y secondusing namespace std;typedef long long LL;const int maxn = 50055;int n, m, ed, tot;struct Edge { int v, w; int next;} E[3 * maxn];int dis[maxn], head[maxn];bool vis[maxn];void AddEdge(int u, int v, int w) { E[tot].v = v; E[tot].w = w; E[tot].next = head[u]; head[u] = tot++;}int bellman(int start) { for(int i = ed; i <= n; i++) dis[i] = 1e8; memset(vis, 0, sizeof vis); dis[start] = 0; queue<int>Q; Q.push(start); while(!Q.empty()) { int x = Q.front(); Q.pop(); vis[x] = 0; for(int e = head[x]; e != -1; e = E[e].next) { if(dis[E[e].v] > dis[x] + E[e].w){ dis[E[e].v] = dis[x] + E[e].w; if(!vis[E[e].v]){ vis[E[e].v] = 1; Q.push(E[e].v); } } } } return -dis[ed];}void init() { while(scanf("%d", &m) > 0) { memset(head, -1, sizeof head); n = -1; ed = 1e8; for(int i = 0; i < m; i++) { int l, r, w; scanf("%d%d%d", &l, &r, &w); n = max(n, r); ed = min(ed, l - 1); AddEdge(r, l - 1, -w); } for(int i = ed + 1; i <= n; i++) { AddEdge(i - 1, i, 1); AddEdge(i, i - 1, 0); } printf("%d\n", bellman(n)); }}int main() {#ifdef LOCAL freopen("in.txt", "r", stdin);#endif // LOCAL init(); /** 将[l,r]中选至少w个可以看成 c[r] - c[l-1] >= w c[i]表示从0到i选多少个 不过这样条件还不够,所以还要再发现 c[i] - c[i-1] >= 0 && c[i]-c[i-1] <= 1 这样就转化成了差分约束 然后跑一遍SPFA,bellman-ford好像会超时。。。 **/ return 0;}
/*poj 1236*/#include <set>#include <cstring>#include <algorithm>#include <iostream>#include <cstdio>#include <cmath>#include <queue>#include <stack>#include <vector>#define mp make_pair#define pb push_back#define X first#define Y secondusing namespace std;typedef long long LL;const int maxn = 105;int n, m, tot = 0, cnt = 0;bool vis[maxn];vector<int>E[maxn];int dfn[maxn], low[maxn],belong[maxn],in[maxn],out[maxn];vector<int>Q[maxn];stack<int>S;void dfs(int u) { dfn[u] = low[u] = ++tot; S.push(u); vis[u] = 1; for(int i = 0; i < (int)E[u].size(); i++) { int v = E[u][i]; if(!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if(vis[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { int v = -1; cnt++; Q[cnt].clear(); while(v != u) { v = S.top(); belong[v] = cnt; S.pop(); vis[v] = 0; Q[cnt].pb(v); } }}void init() { while(scanf("%d", &n) > 0) { cnt = tot = 0; memset(vis,0,sizeof vis); memset(dfn,0,sizeof dfn); memset(in,0,sizeof in); memset(out,0,sizeof out); int v; for(int i = 1; i <= n; i++) while(scanf("%d", &v), v) { E[i].push_back(v); } for(int i = 1; i <= n; i++) if(!dfn[i]) dfs(i); /* for(int i = 0; i < cnt; i++) for(int j = 0; j < Q[i].size(); j++) printf("%d%c", Q[i][j], j == (Q[i].size() - 1) ? '\n' : ' '); */ for(int i=1;i<=n;i++){ for(int j=0;j<E[i].size();j++){ int v = belong[E[i][j]], u = belong[i]; if(u!=v){ out[u]++; in[v]++; } } E[i].clear(); } int a = 0,b = 0; for(int i=1;i<=cnt;i++){ if(!in[i]) a++; if(!out[i]) b++; } if(cnt ==1) printf("1\n0\n"); else printf("%d\n%d\n",a,max(a,b)); }}int main() {#ifdef LOCAL freopen("in.txt", "r", stdin);#endif // LOCAL init(); /** **/ return 0;}
0 0
- g_2 + g_3
- 陆源:阿贝尔对椭圆函数论的贡献[附椭圆函数、模形式(g_2,g_3)、模函数的C++程序计算]
- setIconifiedByDefault() setIconified() onActionViewExpanded()对比
- 简单的MapReduce程序wordCount
- UIFramework之功能分析
- 初学者parseInt()和parseFloat()的理解(仅供参考,老司机笔下留情)
- 使用wxWidgets进行跨平台的C++开发
- g_2 + g_3
- cocos2d-x游戏摇杆开发
- 微痕迹简介
- onclick 点击事件
- 获取客户端IP
- jsp中几种包含页面的方式区别
- 仿京东移动端手指拨动切换轮播图效果
- (笔记)MVC模式
- rman如何在nomount模式下恢复丢失的所有控制文件