初学线性规划
来源:互联网 发布:湖南银楼软件下载 编辑:程序博客网 时间:2024/05/18 01:39
01背包:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 1010;int w[MAXN];int v[MAXN];int dp[MAXN][MAXN];int d[MAXN][MAXN];int main(){ int t; cin>>t; while(t--) { int n,c; scanf("%d %d",&n,&c); int i,j; for(i = 1;i <= n;++i) { scanf("%d",&w[i]); } for(i = 1;i <= n;++i) { scanf("%d",&v[i]); } memset(dp,0,sizeof(dp)); for(i = 0;i <= c;++i) dp[0][i] = 0; for(i = 1;i <= n;++i) { dp[i][0] = 0; for(j = 0;j <= c;++j) { if(j >= v[i]){ //在放入与不放入之间选择,放入之后看i-1个物品容量为j-v[i]的最大重量 dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - v[i]] + w[i]); } else dp[i][j] = dp[i - 1][j];//当前物品不能放入容量为j的背包,直接不放,附上上一个的值 } } printf("%d\n",dp[n][c]); //下面是用滚动数组来进行空间优化的,i总是用到i-1层的值 //在递推法中,如果计算顺序很特殊,而且计算新状态,利用的原状态不多,(从底层状态推出最终状态),可以尝试用滚动数组减少内存输出 memset(d,0,sizeof(d)); for(i = 1;i <= n;++i) { for(j = c;j >= v[i];--j) { //d[j]代表着上一层的d[i - 1][j],d[j - v[i]]代表上一层的d[i - 1][j - v[i]],j必须是逆序,不然在算到d[j - v[i]]已经是d[i][j - v[i]]; d[j] = max(d[j],d[j - v[i]] + w[i]); } } printf("%d\n",d[c]); } return 0;}
DAG上的动态规划:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;//在这里要注意特殊值,-1代表没计算过,inf代表当前的s状态到不了0,其他值则代表状态s到状态0的最长路径长度//将大问题一步一步转移变成小问题const int MAXN = 10010;const int inf = 0x3f3f3f3f;int v[MAXN];int d[MAXN];int vis[MAXN];int w[MAXN];int n;int dp(int s){ int &ans = d[s]; if(vis[s]) return ans; vis[s] = 1; ans = inf;//代表的d[s]到不了0 for(int i = 1;i <= n;++i) { if(s >= w[i]) { ans = min(ans,dp(s - w[i]) + v[i]); //cout<<i<<" "<<w[i]<<" "<<ans<<endl; } } //cout<<ans<<endl; return ans;}void print_ans(int s){ printf("%d ",s); for(int i = 1;i <= n;++i) { if(s >= w[i] && d[s] == d[s - w[i]] + v[i]) { print_ans(s - w[i]); break; } }}int main(){ int t; cin>>t; while(t--){ int E,F; scanf("%d %d",&E,&F); int i,j; scanf("%d",&n); for(i = 1;i <= n;++i) { scanf("%d %d",&v[i],&w[i]); } int s; s = F - E; memset(d,-1,sizeof(d)); memset(vis,0,sizeof(vis)); d[0] = 0; vis[0] = 1; int k = dp(s); if(k == inf) printf("This is impossible.\n"); else{ printf("The minimum amount of money in the piggy-bank is %d.\n",d[s]); } } /*for(i = 0;i <= s;++i) { printf("%d ",d[i]); } printf("\n");*/ return 0;}
多段图的最短路:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 1001;const int inf = 0x3f3f3f3f;int d[MAXN][MAXN];int Next[MAXN][MAXN];int a[MAXN][MAXN];int main(){ int m,n; scanf("%d %d",&m,&n); int i,j; for(i = 0;i < m;++i) { for(j = 0;j < n;++j) { scanf("%d",&a[i][j]); } } int ans = inf,first; //好多动态规划问题都是逆推,因为边界在不在刚开始,总是从边界推出正确的值 for(i = n - 1;i >= 0;--i)//逆推 { for(j = 0;j < m;++j) { if(i == n - 1) d[j][i] = a[j][i]; else{ int row[3] = {j , j - 1 , j + 1}; if(j == 0) row[1] = m - 1; if(j == m - 1) row[2] = 0; sort(row,row + 3);//保证按照字典序,尽量选上面的 d[j][i] = inf; for(int k = 0;k < 3;++k) { int v = d[row[k]][i + 1] + a[j][i]; if(d[j][i] > v){ d[j][i] = v; Next[j][i] = row[k]; } } } //选择最小的出发点 if(i == 0 && d[j][i] < ans){ ans = d[j][i]; first = j; } } } printf("%d",first + 1); for(int i = Next[first][0],j = 1;j < n;i = Next[i][j],++j) printf(" %d",i + 1); printf("\n%d\n",ans); return 0;}
树的最大独立集:
/*一.先简单讲下什么是填表法,什么是刷表法。填表法 :就是一般的动态规划,当前点的状态,可以直接用状态方程,根据之前点的状态推导出来。(如果当前状态既与之前的状态有关,又与之后的状态有关,一般填表法适用于只与之前的状态有关,dp[i]与dp[i - a],dp[i - b],dp[i * 2]有关)刷表法:由当前点的状态,更新其他点的状态。需要注意:只用当每个状态所依赖的状态对它的影响相互独立。*****我认为填表法是当前状态根据状态方程由上一个状态递推出来,不会牵连前几个多个状态。*****刷表法就是当前状态既与之前的状态有关,又与之后的状态有关,从i找i的孩子和孙子,太不方便了,换个角度,用i更新i的父亲和祖父。*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;const int MAXN = 1005;//用可变化二维数组vector来储存vector<int>G[MAXN];//存储边的信息int d[MAXN];//代表节点i的最大独立集大小int f[MAXN];//存储i节点的根节点int wide[MAXN];//代表了该节点在第几层int Cmax[MAXN];//i孩子的dp和int Smax[MAXN];//i孙子的dp和int wide_Max;//将无根树建成有根树的最高层也就是叶子节点那儿int n;//节点数//将树打印出来void print_Tree(){ for(int i = 1;i <= n;++i) { printf("%d: ",i); for(int j = 0;j < G[i].size();++j) { printf("%d ",G[i][j]); } printf("\n"); }}void ReadTree(){ scanf("%d",&n); for(int i = 0;i < n - 1;++i) { int s,e; scanf("%d %d",&s,&e); G[s].push_back(e); G[e].push_back(s); }}//将无根树建成有根树//建立以v为根节点的树void dfs(int v,int fa){ int d = G[v].size(); //记录该节点的层数 wide[v] = fa == -1 ? 0 : wide[fa] + 1; //一直更新最大层数 if(wide[v] > wide_Max) wide_Max = wide[v]; //遍历所连接的每个点 for(int i = 0;i < d;++i) { int k = G[v][i]; //这里防止出现死递归,不能将自己的父亲节点再认为儿子 if(k != fa) dfs(k,f[k] = v); }}int rootDP(int root){ //初始化根节点的父亲节点 f[root] = -1; //初始化最大层数 wide_Max = -1; //建立以root为根的树 dfs(root,-1); //从叶子节点往上推,用刷表法更新i的父亲和祖父 for(int i = wide_Max;i >= 0;--i) { //遍历节点找出来所在层数对应的节点 for(int j = 1;j <= n;++j) { if(wide[j] == i) { d[j] = max(Cmax[j],Smax[j] + 1); if(i >= 1)//至少有一个孩子 Cmax[f[i]] += d[i]; if(i >= 2)//至少有孩子和孙子 Smax[f[f[i]]] += d[i]; } } }}int solve(){ int ans = 0; for(int i = 1;i <= n;++i) { memset(Cmax,0,sizeof(Cmax)); memset(Smax,0,sizeof(Smax)); int tmp = rootDP(i); ans = max(ans,tmp); } return ans;}int main(){ ReadTree(); print_Tree(); return 0;}
最优矩阵链乘::
//线性DP/*最优矩阵链乘:f(i,j) = min{f(i,k) + f(k + 1,j) + p[i - 1]*p[k]*p[r]}*//*#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 105;const int inf = 0x3f3f3f3f;int d[MAXN][MAXN];int p[MAXN];int n;int dp(int l,int r){ int &ans = d[l][r]; if(ans != -1) return ans;//这步叫记忆化搜索 if(l == r) return ans = 0; if(l + 1 == r){qq return ans = p[l - 1] * p[l] * p[r]; } //这里进来说明d[l][r]没计算过,要将之初始化。(还是特殊值) ans = inf; for(int k = l + 1;k < r;++k) { ans = min(ans,dp(l,k) + dp(k + 1,r) + p[l - 1] * p[k] * p[r]); } return ans;}int main(){ while(~scanf("%d",&n)) { int i,j; for(i = 0;i < n;++i) { scanf("%d",&p[i]); } memset(d,-1,sizeof(d)); int m = dp(1,n - 1); printf("%d\n",m); } return 0;}*/
最优三角剖分:
/* 最优三角剖分,d(i,j) = max{d(i,k) + d(k,j) + w(i,j,k)}*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 105;int d[MAXN][MAXN];int w[MAXN];int n;int dp(int i,int j){ int &ans = d[i][j]; if(ans != -1) return ans; if(j == i + 1) return ans = 0; if(j == i + 2){ return ans = w[i] + w[i + 1] + w[i + 2]; } ans = -(1<<30); for(int k = 1;k <= n;++k) { ans = max(ans,dp(i,k) + dp(k,j) + w[i] + w[j] + w[k]); } return ans;}int main(){ while(~scanf("%d",&n)) { int i,j; for(i = 1;i <= n;++i) { scanf("%d",&w[i]); } memset(d,-1,sizeof(d)); int m = dp(1,n); printf("%d\n",m); } return 0;}
阅读全文
0 0
- 初学线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划
- 线性规划法
- 线性规划入门
- 实战百度天工云
- spark
- NO.1 基于verilogHDL的时钟分频与任意占空比调节
- 前导码,时域测量和频域测量
- AngularJs请求json字符串
- 初学线性规划
- C++ REST SDK(C++语言客户端-服务器通信库)
- (QT)QT跳转页面(信号-槽机制)
- HDU 2844:Coins (完全背包)
- 【C#】常量
- 数据结构
- python 实现 mapreducer
- c++中string erase函数的使用
- python常用模块